// 开始：建造！nethttpomithttp2 
// /+构建！nethttpomithttp2 

// 由golang生成的代码。org/x/tools/cmd/bundle。不要编辑。
// /$bundle-o=h2_bundle。go-prefix=http2-tags=！nethttpomithttp2 golang。org/x/net/http2 

// 包http2实现HTTP/2协议。
// 
// 这个软件包是低级的，打算由非常
// 的人直接使用。大多数用户将通过自动
// net/http包（Go 1.6及更高版本）间接使用它。
// 有关在早期Go版本中使用的信息，请参阅ConfigureServer。（传输支持
// 需要Go 1.6或更高版本）
// 
// 请参阅https:
// 参见https:
// 

package http

import (
	"bufio"
	"bytes"
	"compress/gzip"
	"context"
	"crypto/rand"
	"crypto/tls"
	"encoding/binary"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"math"
	mathrand "math/rand"
	"net"
	"net/http/httptrace"
	"net/textproto"
	"net/url"
	"os"
	"reflect"
	"runtime"
	"sort"
	"strconv"
	"strings"
	"sync"
	"sync/atomic"
	"time"

	"golang.org/x/net/http/httpguts"
	"golang.org/x/net/http2/hpack"
	"golang.org/x/net/idna"
)

// HTTP协议是根据ASCII而不是Unicode定义的。此文件
// 包含帮助函数，这些函数可能使用Unicode感知函数，否则将不安全，如果使用不当，可能会引入漏洞。

// asciiEqualFold是字符串。等倍，仅限ASCII码。它报告s和t 
// 是否相等，ASCII大小写不敏感。
func http2asciiEqualFold(s, t string) bool {
	if len(s) != len(t) {
		return false
	}
	for i := 0; i < len(s); i++ {
		if http2lower(s[i]) != http2lower(t[i]) {
			return false
		}
	}
	return true
}

// lower返回b的ASCII小写版本。
func http2lower(b byte) byte {
	if 'A' <= b && b <= 'Z' {
		return b + ('a' - 'A')
	}
	return b
}

// isASCIIPrint返回s是否为ASCII，是否可根据
// https:
func http2isASCIIPrint(s string) bool {
	for i := 0; i < len(s); i++ {
		if s[i] < ' ' || s[i] > '~' {
			return false
		}
	}
	return true
}

// asciiToLower返回s的小写版本（如果s是ASCII且可打印的），
// 以及它是否是。
func http2asciiToLower(s string) (lower string, ok bool) {
	if !http2isASCIIPrint(s) {
		return "", false
	}
	return strings.ToLower(s), true
}

// 可能的密码套件ID列表。摘自
// https:

const (
	http2cipher_TLS_NULL_WITH_NULL_NULL               uint16 = 0x0000
	http2cipher_TLS_RSA_WITH_NULL_MD5                 uint16 = 0x0001
	http2cipher_TLS_RSA_WITH_NULL_SHA                 uint16 = 0x0002
	http2cipher_TLS_RSA_EXPORT_WITH_RC4_40_MD5        uint16 = 0x0003
	http2cipher_TLS_RSA_WITH_RC4_128_MD5              uint16 = 0x0004
	http2cipher_TLS_RSA_WITH_RC4_128_SHA              uint16 = 0x0005
	http2cipher_TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5    uint16 = 0x0006
	http2cipher_TLS_RSA_WITH_IDEA_CBC_SHA             uint16 = 0x0007
	http2cipher_TLS_RSA_EXPORT_WITH_DES40_CBC_SHA     uint16 = 0x0008
	http2cipher_TLS_RSA_WITH_DES_CBC_SHA              uint16 = 0x0009
	http2cipher_TLS_RSA_WITH_3DES_EDE_CBC_SHA         uint16 = 0x000A
	http2cipher_TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA  uint16 = 0x000B
	http2cipher_TLS_DH_DSS_WITH_DES_CBC_SHA           uint16 = 0x000C
	http2cipher_TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA      uint16 = 0x000D
	http2cipher_TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA  uint16 = 0x000E
	http2cipher_TLS_DH_RSA_WITH_DES_CBC_SHA           uint16 = 0x000F
	http2cipher_TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA      uint16 = 0x0010
	http2cipher_TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA uint16 = 0x0011
	http2cipher_TLS_DHE_DSS_WITH_DES_CBC_SHA          uint16 = 0x0012
	http2cipher_TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA     uint16 = 0x0013
	http2cipher_TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA uint16 = 0x0014
	http2cipher_TLS_DHE_RSA_WITH_DES_CBC_SHA          uint16 = 0x0015
	http2cipher_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA     uint16 = 0x0016
	http2cipher_TLS_DH_anon_EXPORT_WITH_RC4_40_MD5    uint16 = 0x0017
	http2cipher_TLS_DH_anon_WITH_RC4_128_MD5          uint16 = 0x0018
	http2cipher_TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA uint16 = 0x0019
	http2cipher_TLS_DH_anon_WITH_DES_CBC_SHA          uint16 = 0x001A
	http2cipher_TLS_DH_anon_WITH_3DES_EDE_CBC_SHA     uint16 = 0x001B
	// 保留uint16=0x001C-1D 
	http2cipher_TLS_KRB5_WITH_DES_CBC_SHA             uint16 = 0x001E
	http2cipher_TLS_KRB5_WITH_3DES_EDE_CBC_SHA        uint16 = 0x001F
	http2cipher_TLS_KRB5_WITH_RC4_128_SHA             uint16 = 0x0020
	http2cipher_TLS_KRB5_WITH_IDEA_CBC_SHA            uint16 = 0x0021
	http2cipher_TLS_KRB5_WITH_DES_CBC_MD5             uint16 = 0x0022
	http2cipher_TLS_KRB5_WITH_3DES_EDE_CBC_MD5        uint16 = 0x0023
	http2cipher_TLS_KRB5_WITH_RC4_128_MD5             uint16 = 0x0024
	http2cipher_TLS_KRB5_WITH_IDEA_CBC_MD5            uint16 = 0x0025
	http2cipher_TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA   uint16 = 0x0026
	http2cipher_TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA   uint16 = 0x0027
	http2cipher_TLS_KRB5_EXPORT_WITH_RC4_40_SHA       uint16 = 0x0028
	http2cipher_TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5   uint16 = 0x0029
	http2cipher_TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5   uint16 = 0x002A
	http2cipher_TLS_KRB5_EXPORT_WITH_RC4_40_MD5       uint16 = 0x002B
	http2cipher_TLS_PSK_WITH_NULL_SHA                 uint16 = 0x002C
	http2cipher_TLS_DHE_PSK_WITH_NULL_SHA             uint16 = 0x002D
	http2cipher_TLS_RSA_PSK_WITH_NULL_SHA             uint16 = 0x002E
	http2cipher_TLS_RSA_WITH_AES_128_CBC_SHA          uint16 = 0x002F
	http2cipher_TLS_DH_DSS_WITH_AES_128_CBC_SHA       uint16 = 0x0030
	http2cipher_TLS_DH_RSA_WITH_AES_128_CBC_SHA       uint16 = 0x0031
	http2cipher_TLS_DHE_DSS_WITH_AES_128_CBC_SHA      uint16 = 0x0032
	http2cipher_TLS_DHE_RSA_WITH_AES_128_CBC_SHA      uint16 = 0x0033
	http2cipher_TLS_DH_anon_WITH_AES_128_CBC_SHA      uint16 = 0x0034
	http2cipher_TLS_RSA_WITH_AES_256_CBC_SHA          uint16 = 0x0035
	http2cipher_TLS_DH_DSS_WITH_AES_256_CBC_SHA       uint16 = 0x0036
	http2cipher_TLS_DH_RSA_WITH_AES_256_CBC_SHA       uint16 = 0x0037
	http2cipher_TLS_DHE_DSS_WITH_AES_256_CBC_SHA      uint16 = 0x0038
	http2cipher_TLS_DHE_RSA_WITH_AES_256_CBC_SHA      uint16 = 0x0039
	http2cipher_TLS_DH_anon_WITH_AES_256_CBC_SHA      uint16 = 0x003A
	http2cipher_TLS_RSA_WITH_NULL_SHA256              uint16 = 0x003B
	http2cipher_TLS_RSA_WITH_AES_128_CBC_SHA256       uint16 = 0x003C
	http2cipher_TLS_RSA_WITH_AES_256_CBC_SHA256       uint16 = 0x003D
	http2cipher_TLS_DH_DSS_WITH_AES_128_CBC_SHA256    uint16 = 0x003E
	http2cipher_TLS_DH_RSA_WITH_AES_128_CBC_SHA256    uint16 = 0x003F
	http2cipher_TLS_DHE_DSS_WITH_AES_128_CBC_SHA256   uint16 = 0x0040
	http2cipher_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA     uint16 = 0x0041
	http2cipher_TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA  uint16 = 0x0042
	http2cipher_TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA  uint16 = 0x0043
	http2cipher_TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA uint16 = 0x0044
	http2cipher_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA uint16 = 0x0045
	http2cipher_TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA uint16 = 0x0046
	// 保留uint16=0x0047-4F 
	// 保留uint16=0x0050-58 
	// 保留uint16=0x0059-5C 
	// 保留uint16=0x0060-66 
	http2cipher_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 uint16 = 0x0067
	http2cipher_TLS_DH_DSS_WITH_AES_256_CBC_SHA256  uint16 = 0x0068
	http2cipher_TLS_DH_RSA_WITH_AES_256_CBC_SHA256  uint16 = 0x0069
	http2cipher_TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 uint16 = 0x006A
	http2cipher_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 uint16 = 0x006B
	http2cipher_TLS_DH_anon_WITH_AES_128_CBC_SHA256 uint16 = 0x006C
	http2cipher_TLS_DH_anon_WITH_AES_256_CBC_SHA256 uint16 = 0x006D
	// 未分配uint16=0xE-255
	http2cipher_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA        uint16 = 0x0084
	http2cipher_TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA     uint16 = 0x0085
	http2cipher_TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA     uint16 = 0x0086
	http2cipher_TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA    uint16 = 0x0087
	http2cipher_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA    uint16 = 0x0088
	http2cipher_TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA    uint16 = 0x0089
	http2cipher_TLS_PSK_WITH_RC4_128_SHA                 uint16 = 0x008A
	http2cipher_TLS_PSK_WITH_3DES_EDE_CBC_SHA            uint16 = 0x008B
	http2cipher_TLS_PSK_WITH_AES_128_CBC_SHA             uint16 = 0x008C
	http2cipher_TLS_PSK_WITH_AES_256_CBC_SHA             uint16 = 0x008D
	http2cipher_TLS_DHE_PSK_WITH_RC4_128_SHA             uint16 = 0x008E
	http2cipher_TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA        uint16 = 0x008F
	http2cipher_TLS_DHE_PSK_WITH_AES_128_CBC_SHA         uint16 = 0x0090
	http2cipher_TLS_DHE_PSK_WITH_AES_256_CBC_SHA         uint16 = 0x0091
	http2cipher_TLS_RSA_PSK_WITH_RC4_128_SHA             uint16 = 0x0092
	http2cipher_TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA        uint16 = 0x0093
	http2cipher_TLS_RSA_PSK_WITH_AES_128_CBC_SHA         uint16 = 0x0094
	http2cipher_TLS_RSA_PSK_WITH_AES_256_CBC_SHA         uint16 = 0x0095
	http2cipher_TLS_RSA_WITH_SEED_CBC_SHA                uint16 = 0x0096
	http2cipher_TLS_DH_DSS_WITH_SEED_CBC_SHA             uint16 = 0x0097
	http2cipher_TLS_DH_RSA_WITH_SEED_CBC_SHA             uint16 = 0x0098
	http2cipher_TLS_DHE_DSS_WITH_SEED_CBC_SHA            uint16 = 0x0099
	http2cipher_TLS_DHE_RSA_WITH_SEED_CBC_SHA            uint16 = 0x009A
	http2cipher_TLS_DH_anon_WITH_SEED_CBC_SHA            uint16 = 0x009B
	http2cipher_TLS_RSA_WITH_AES_128_GCM_SHA256          uint16 = 0x009C
	http2cipher_TLS_RSA_WITH_AES_256_GCM_SHA384          uint16 = 0x009D
	http2cipher_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256      uint16 = 0x009E
	http2cipher_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384      uint16 = 0x009F
	http2cipher_TLS_DH_RSA_WITH_AES_128_GCM_SHA256       uint16 = 0x00A0
	http2cipher_TLS_DH_RSA_WITH_AES_256_GCM_SHA384       uint16 = 0x00A1
	http2cipher_TLS_DHE_DSS_WITH_AES_128_GCM_SHA256      uint16 = 0x00A2
	http2cipher_TLS_DHE_DSS_WITH_AES_256_GCM_SHA384      uint16 = 0x00A3
	http2cipher_TLS_DH_DSS_WITH_AES_128_GCM_SHA256       uint16 = 0x00A4
	http2cipher_TLS_DH_DSS_WITH_AES_256_GCM_SHA384       uint16 = 0x00A5
	http2cipher_TLS_DH_anon_WITH_AES_128_GCM_SHA256      uint16 = 0x00A6
	http2cipher_TLS_DH_anon_WITH_AES_256_GCM_SHA384      uint16 = 0x00A7
	http2cipher_TLS_PSK_WITH_AES_128_GCM_SHA256          uint16 = 0x00A8
	http2cipher_TLS_PSK_WITH_AES_256_GCM_SHA384          uint16 = 0x00A9
	http2cipher_TLS_DHE_PSK_WITH_AES_128_GCM_SHA256      uint16 = 0x00AA
	http2cipher_TLS_DHE_PSK_WITH_AES_256_GCM_SHA384      uint16 = 0x00AB
	http2cipher_TLS_RSA_PSK_WITH_AES_128_GCM_SHA256      uint16 = 0x00AC
	http2cipher_TLS_RSA_PSK_WITH_AES_256_GCM_SHA384      uint16 = 0x00AD
	http2cipher_TLS_PSK_WITH_AES_128_CBC_SHA256          uint16 = 0x00AE
	http2cipher_TLS_PSK_WITH_AES_256_CBC_SHA384          uint16 = 0x00AF
	http2cipher_TLS_PSK_WITH_NULL_SHA256                 uint16 = 0x00B0
	http2cipher_TLS_PSK_WITH_NULL_SHA384                 uint16 = 0x00B1
	http2cipher_TLS_DHE_PSK_WITH_AES_128_CBC_SHA256      uint16 = 0x00B2
	http2cipher_TLS_DHE_PSK_WITH_AES_256_CBC_SHA384      uint16 = 0x00B3
	http2cipher_TLS_DHE_PSK_WITH_NULL_SHA256             uint16 = 0x00B4
	http2cipher_TLS_DHE_PSK_WITH_NULL_SHA384             uint16 = 0x00B5
	http2cipher_TLS_RSA_PSK_WITH_AES_128_CBC_SHA256      uint16 = 0x00B6
	http2cipher_TLS_RSA_PSK_WITH_AES_256_CBC_SHA384      uint16 = 0x00B7
	http2cipher_TLS_RSA_PSK_WITH_NULL_SHA256             uint16 = 0x00B8
	http2cipher_TLS_RSA_PSK_WITH_NULL_SHA384             uint16 = 0x00B9
	http2cipher_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256     uint16 = 0x00BA
	http2cipher_TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256  uint16 = 0x00BB
	http2cipher_TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256  uint16 = 0x00BC
	http2cipher_TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256 uint16 = 0x00BD
	http2cipher_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 uint16 = 0x00BE
	http2cipher_TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256 uint16 = 0x00BF
	http2cipher_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256     uint16 = 0x00C0
	http2cipher_TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256  uint16 = 0x00C1
	http2cipher_TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256  uint16 = 0x00C2
	http2cipher_TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256 uint16 = 0x00C3
	http2cipher_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 uint16 = 0x00C4
	http2cipher_TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256 uint16 = 0x00C5
	http2cipher_TLS_EMPTY_RENEGOTIATION_INFO_SCSV uint16 = 0x00FF
	// 未分配uint16=0x01-55，*
	http2cipher_TLS_FALLBACK_SCSV uint16 = 0x5600
	// 未分配uint16=0x5601-0xC000 
	http2cipher_TLS_ECDH_ECDSA_WITH_NULL_SHA                 uint16 = 0xC001
	http2cipher_TLS_ECDH_ECDSA_WITH_RC4_128_SHA              uint16 = 0xC002
	http2cipher_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA         uint16 = 0xC003
	http2cipher_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA          uint16 = 0xC004
	http2cipher_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA          uint16 = 0xC005
	http2cipher_TLS_ECDHE_ECDSA_WITH_NULL_SHA                uint16 = 0xC006
	http2cipher_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA             uint16 = 0xC007
	http2cipher_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA        uint16 = 0xC008
	http2cipher_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA         uint16 = 0xC009
	http2cipher_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA         uint16 = 0xC00A
	http2cipher_TLS_ECDH_RSA_WITH_NULL_SHA                   uint16 = 0xC00B
	http2cipher_TLS_ECDH_RSA_WITH_RC4_128_SHA                uint16 = 0xC00C
	http2cipher_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA           uint16 = 0xC00D
	http2cipher_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA            uint16 = 0xC00E
	http2cipher_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA            uint16 = 0xC00F
	http2cipher_TLS_ECDHE_RSA_WITH_NULL_SHA                  uint16 = 0xC010
	http2cipher_TLS_ECDHE_RSA_WITH_RC4_128_SHA               uint16 = 0xC011
	http2cipher_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA          uint16 = 0xC012
	http2cipher_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA           uint16 = 0xC013
	http2cipher_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA           uint16 = 0xC014
	http2cipher_TLS_ECDH_anon_WITH_NULL_SHA                  uint16 = 0xC015
	http2cipher_TLS_ECDH_anon_WITH_RC4_128_SHA               uint16 = 0xC016
	http2cipher_TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA          uint16 = 0xC017
	http2cipher_TLS_ECDH_anon_WITH_AES_128_CBC_SHA           uint16 = 0xC018
	http2cipher_TLS_ECDH_anon_WITH_AES_256_CBC_SHA           uint16 = 0xC019
	http2cipher_TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA            uint16 = 0xC01A
	http2cipher_TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA        uint16 = 0xC01B
	http2cipher_TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA        uint16 = 0xC01C
	http2cipher_TLS_SRP_SHA_WITH_AES_128_CBC_SHA             uint16 = 0xC01D
	http2cipher_TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA         uint16 = 0xC01E
	http2cipher_TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA         uint16 = 0xC01F
	http2cipher_TLS_SRP_SHA_WITH_AES_256_CBC_SHA             uint16 = 0xC020
	http2cipher_TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA         uint16 = 0xC021
	http2cipher_TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA         uint16 = 0xC022
	http2cipher_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256      uint16 = 0xC023
	http2cipher_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384      uint16 = 0xC024
	http2cipher_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256       uint16 = 0xC025
	http2cipher_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384       uint16 = 0xC026
	http2cipher_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256        uint16 = 0xC027
	http2cipher_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384        uint16 = 0xC028
	http2cipher_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256         uint16 = 0xC029
	http2cipher_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384         uint16 = 0xC02A
	http2cipher_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256      uint16 = 0xC02B
	http2cipher_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384      uint16 = 0xC02C
	http2cipher_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256       uint16 = 0xC02D
	http2cipher_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384       uint16 = 0xC02E
	http2cipher_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256        uint16 = 0xC02F
	http2cipher_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384        uint16 = 0xC030
	http2cipher_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256         uint16 = 0xC031
	http2cipher_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384         uint16 = 0xC032
	http2cipher_TLS_ECDHE_PSK_WITH_RC4_128_SHA               uint16 = 0xC033
	http2cipher_TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA          uint16 = 0xC034
	http2cipher_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA           uint16 = 0xC035
	http2cipher_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA           uint16 = 0xC036
	http2cipher_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256        uint16 = 0xC037
	http2cipher_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384        uint16 = 0xC038
	http2cipher_TLS_ECDHE_PSK_WITH_NULL_SHA                  uint16 = 0xC039
	http2cipher_TLS_ECDHE_PSK_WITH_NULL_SHA256               uint16 = 0xC03A
	http2cipher_TLS_ECDHE_PSK_WITH_NULL_SHA384               uint16 = 0xC03B
	http2cipher_TLS_RSA_WITH_ARIA_128_CBC_SHA256             uint16 = 0xC03C
	http2cipher_TLS_RSA_WITH_ARIA_256_CBC_SHA384             uint16 = 0xC03D
	http2cipher_TLS_DH_DSS_WITH_ARIA_128_CBC_SHA256          uint16 = 0xC03E
	http2cipher_TLS_DH_DSS_WITH_ARIA_256_CBC_SHA384          uint16 = 0xC03F
	http2cipher_TLS_DH_RSA_WITH_ARIA_128_CBC_SHA256          uint16 = 0xC040
	http2cipher_TLS_DH_RSA_WITH_ARIA_256_CBC_SHA384          uint16 = 0xC041
	http2cipher_TLS_DHE_DSS_WITH_ARIA_128_CBC_SHA256         uint16 = 0xC042
	http2cipher_TLS_DHE_DSS_WITH_ARIA_256_CBC_SHA384         uint16 = 0xC043
	http2cipher_TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256         uint16 = 0xC044
	http2cipher_TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384         uint16 = 0xC045
	http2cipher_TLS_DH_anon_WITH_ARIA_128_CBC_SHA256         uint16 = 0xC046
	http2cipher_TLS_DH_anon_WITH_ARIA_256_CBC_SHA384         uint16 = 0xC047
	http2cipher_TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256     uint16 = 0xC048
	http2cipher_TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384     uint16 = 0xC049
	http2cipher_TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256      uint16 = 0xC04A
	http2cipher_TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384      uint16 = 0xC04B
	http2cipher_TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256       uint16 = 0xC04C
	http2cipher_TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384       uint16 = 0xC04D
	http2cipher_TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256        uint16 = 0xC04E
	http2cipher_TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384        uint16 = 0xC04F
	http2cipher_TLS_RSA_WITH_ARIA_128_GCM_SHA256             uint16 = 0xC050
	http2cipher_TLS_RSA_WITH_ARIA_256_GCM_SHA384             uint16 = 0xC051
	http2cipher_TLS_DHE_RSA_WITH_ARIA_128_GCM_SHA256         uint16 = 0xC052
	http2cipher_TLS_DHE_RSA_WITH_ARIA_256_GCM_SHA384         uint16 = 0xC053
	http2cipher_TLS_DH_RSA_WITH_ARIA_128_GCM_SHA256          uint16 = 0xC054
	http2cipher_TLS_DH_RSA_WITH_ARIA_256_GCM_SHA384          uint16 = 0xC055
	http2cipher_TLS_DHE_DSS_WITH_ARIA_128_GCM_SHA256         uint16 = 0xC056
	http2cipher_TLS_DHE_DSS_WITH_ARIA_256_GCM_SHA384         uint16 = 0xC057
	http2cipher_TLS_DH_DSS_WITH_ARIA_128_GCM_SHA256          uint16 = 0xC058
	http2cipher_TLS_DH_DSS_WITH_ARIA_256_GCM_SHA384          uint16 = 0xC059
	http2cipher_TLS_DH_anon_WITH_ARIA_128_GCM_SHA256         uint16 = 0xC05A
	http2cipher_TLS_DH_anon_WITH_ARIA_256_GCM_SHA384         uint16 = 0xC05B
	http2cipher_TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256     uint16 = 0xC05C
	http2cipher_TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384     uint16 = 0xC05D
	http2cipher_TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256      uint16 = 0xC05E
	http2cipher_TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384      uint16 = 0xC05F
	http2cipher_TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256       uint16 = 0xC060
	http2cipher_TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384       uint16 = 0xC061
	http2cipher_TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256        uint16 = 0xC062
	http2cipher_TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384        uint16 = 0xC063
	http2cipher_TLS_PSK_WITH_ARIA_128_CBC_SHA256             uint16 = 0xC064
	http2cipher_TLS_PSK_WITH_ARIA_256_CBC_SHA384             uint16 = 0xC065
	http2cipher_TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256         uint16 = 0xC066
	http2cipher_TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384         uint16 = 0xC067
	http2cipher_TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256         uint16 = 0xC068
	http2cipher_TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384         uint16 = 0xC069
	http2cipher_TLS_PSK_WITH_ARIA_128_GCM_SHA256             uint16 = 0xC06A
	http2cipher_TLS_PSK_WITH_ARIA_256_GCM_SHA384             uint16 = 0xC06B
	http2cipher_TLS_DHE_PSK_WITH_ARIA_128_GCM_SHA256         uint16 = 0xC06C
	http2cipher_TLS_DHE_PSK_WITH_ARIA_256_GCM_SHA384         uint16 = 0xC06D
	http2cipher_TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256         uint16 = 0xC06E
	http2cipher_TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384         uint16 = 0xC06F
	http2cipher_TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256       uint16 = 0xC070
	http2cipher_TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384       uint16 = 0xC071
	http2cipher_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 uint16 = 0xC072
	http2cipher_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 uint16 = 0xC073
	http2cipher_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256  uint16 = 0xC074
	http2cipher_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384  uint16 = 0xC075
	http2cipher_TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256   uint16 = 0xC076
	http2cipher_TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384   uint16 = 0xC077
	http2cipher_TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256    uint16 = 0xC078
	http2cipher_TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384    uint16 = 0xC079
	http2cipher_TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256         uint16 = 0xC07A
	http2cipher_TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384         uint16 = 0xC07B
	http2cipher_TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256     uint16 = 0xC07C
	http2cipher_TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384     uint16 = 0xC07D
	http2cipher_TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256      uint16 = 0xC07E
	http2cipher_TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384      uint16 = 0xC07F
	http2cipher_TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256     uint16 = 0xC080
	http2cipher_TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384     uint16 = 0xC081
	http2cipher_TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256      uint16 = 0xC082
	http2cipher_TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384      uint16 = 0xC083
	http2cipher_TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256     uint16 = 0xC084
	http2cipher_TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384     uint16 = 0xC085
	http2cipher_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 uint16 = 0xC086
	http2cipher_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 uint16 = 0xC087
	http2cipher_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256  uint16 = 0xC088
	http2cipher_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384  uint16 = 0xC089
	http2cipher_TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256   uint16 = 0xC08A
	http2cipher_TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384   uint16 = 0xC08B
	http2cipher_TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256    uint16 = 0xC08C
	http2cipher_TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384    uint16 = 0xC08D
	http2cipher_TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256         uint16 = 0xC08E
	http2cipher_TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384         uint16 = 0xC08F
	http2cipher_TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256     uint16 = 0xC090
	http2cipher_TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384     uint16 = 0xC091
	http2cipher_TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256     uint16 = 0xC092
	http2cipher_TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384     uint16 = 0xC093
	http2cipher_TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256         uint16 = 0xC094
	http2cipher_TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384         uint16 = 0xC095
	http2cipher_TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256     uint16 = 0xC096
	http2cipher_TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384     uint16 = 0xC097
	http2cipher_TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256     uint16 = 0xC098
	http2cipher_TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384     uint16 = 0xC099
	http2cipher_TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256   uint16 = 0xC09A
	http2cipher_TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384   uint16 = 0xC09B
	http2cipher_TLS_RSA_WITH_AES_128_CCM                     uint16 = 0xC09C
	http2cipher_TLS_RSA_WITH_AES_256_CCM                     uint16 = 0xC09D
	http2cipher_TLS_DHE_RSA_WITH_AES_128_CCM                 uint16 = 0xC09E
	http2cipher_TLS_DHE_RSA_WITH_AES_256_CCM                 uint16 = 0xC09F
	http2cipher_TLS_RSA_WITH_AES_128_CCM_8                   uint16 = 0xC0A0
	http2cipher_TLS_RSA_WITH_AES_256_CCM_8                   uint16 = 0xC0A1
	http2cipher_TLS_DHE_RSA_WITH_AES_128_CCM_8               uint16 = 0xC0A2
	http2cipher_TLS_DHE_RSA_WITH_AES_256_CCM_8               uint16 = 0xC0A3
	http2cipher_TLS_PSK_WITH_AES_128_CCM                     uint16 = 0xC0A4
	http2cipher_TLS_PSK_WITH_AES_256_CCM                     uint16 = 0xC0A5
	http2cipher_TLS_DHE_PSK_WITH_AES_128_CCM                 uint16 = 0xC0A6
	http2cipher_TLS_DHE_PSK_WITH_AES_256_CCM                 uint16 = 0xC0A7
	http2cipher_TLS_PSK_WITH_AES_128_CCM_8                   uint16 = 0xC0A8
	http2cipher_TLS_PSK_WITH_AES_256_CCM_8                   uint16 = 0xC0A9
	http2cipher_TLS_PSK_DHE_WITH_AES_128_CCM_8               uint16 = 0xC0AA
	http2cipher_TLS_PSK_DHE_WITH_AES_256_CCM_8               uint16 = 0xC0AB
	http2cipher_TLS_ECDHE_ECDSA_WITH_AES_128_CCM             uint16 = 0xC0AC
	http2cipher_TLS_ECDHE_ECDSA_WITH_AES_256_CCM             uint16 = 0xC0AD
	http2cipher_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8           uint16 = 0xC0AE
	http2cipher_TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8           uint16 = 0xC0AF
	// 未分配uint16=0xC0B0 FF 
	// 未分配uint16=0xC1 CB，*
	// 未分配uint16=0xCC00-A7 
	http2cipher_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256   uint16 = 0xCCA8
	http2cipher_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 uint16 = 0xCCA9
	http2cipher_TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256     uint16 = 0xCCAA
	http2cipher_TLS_PSK_WITH_CHACHA20_POLY1305_SHA256         uint16 = 0xCCAB
	http2cipher_TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256   uint16 = 0xCCAC
	http2cipher_TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256     uint16 = 0xCCAD
	http2cipher_TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256     uint16 = 0xCCAE
)

// isBadCipher报告密码是否被HTTP/2规范列入黑名单。
// 参考文献：
// https:
// 拒绝附录A中的密码套件。
// “此列表包括那些不提供临时密钥交换的密码套件，以及那些基于TLS null、流或分组密码类型的
func http2isBadCipher(cipher uint16) bool {
	switch cipher {
	case http2cipher_TLS_NULL_WITH_NULL_NULL,
		http2cipher_TLS_RSA_WITH_NULL_MD5,
		http2cipher_TLS_RSA_WITH_NULL_SHA,
		http2cipher_TLS_RSA_EXPORT_WITH_RC4_40_MD5,
		http2cipher_TLS_RSA_WITH_RC4_128_MD5,
		http2cipher_TLS_RSA_WITH_RC4_128_SHA,
		http2cipher_TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5,
		http2cipher_TLS_RSA_WITH_IDEA_CBC_SHA,
		http2cipher_TLS_RSA_EXPORT_WITH_DES40_CBC_SHA,
		http2cipher_TLS_RSA_WITH_DES_CBC_SHA,
		http2cipher_TLS_RSA_WITH_3DES_EDE_CBC_SHA,
		http2cipher_TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA,
		http2cipher_TLS_DH_DSS_WITH_DES_CBC_SHA,
		http2cipher_TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA,
		http2cipher_TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA,
		http2cipher_TLS_DH_RSA_WITH_DES_CBC_SHA,
		http2cipher_TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA,
		http2cipher_TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA,
		http2cipher_TLS_DHE_DSS_WITH_DES_CBC_SHA,
		http2cipher_TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA,
		http2cipher_TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA,
		http2cipher_TLS_DHE_RSA_WITH_DES_CBC_SHA,
		http2cipher_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA,
		http2cipher_TLS_DH_anon_EXPORT_WITH_RC4_40_MD5,
		http2cipher_TLS_DH_anon_WITH_RC4_128_MD5,
		http2cipher_TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA,
		http2cipher_TLS_DH_anon_WITH_DES_CBC_SHA,
		http2cipher_TLS_DH_anon_WITH_3DES_EDE_CBC_SHA,
		http2cipher_TLS_KRB5_WITH_DES_CBC_SHA,
		http2cipher_TLS_KRB5_WITH_3DES_EDE_CBC_SHA,
		http2cipher_TLS_KRB5_WITH_RC4_128_SHA,
		http2cipher_TLS_KRB5_WITH_IDEA_CBC_SHA,
		http2cipher_TLS_KRB5_WITH_DES_CBC_MD5,
		http2cipher_TLS_KRB5_WITH_3DES_EDE_CBC_MD5,
		http2cipher_TLS_KRB5_WITH_RC4_128_MD5,
		http2cipher_TLS_KRB5_WITH_IDEA_CBC_MD5,
		http2cipher_TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA,
		http2cipher_TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA,
		http2cipher_TLS_KRB5_EXPORT_WITH_RC4_40_SHA,
		http2cipher_TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5,
		http2cipher_TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5,
		http2cipher_TLS_KRB5_EXPORT_WITH_RC4_40_MD5,
		http2cipher_TLS_PSK_WITH_NULL_SHA,
		http2cipher_TLS_DHE_PSK_WITH_NULL_SHA,
		http2cipher_TLS_RSA_PSK_WITH_NULL_SHA,
		http2cipher_TLS_RSA_WITH_AES_128_CBC_SHA,
		http2cipher_TLS_DH_DSS_WITH_AES_128_CBC_SHA,
		http2cipher_TLS_DH_RSA_WITH_AES_128_CBC_SHA,
		http2cipher_TLS_DHE_DSS_WITH_AES_128_CBC_SHA,
		http2cipher_TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
		http2cipher_TLS_DH_anon_WITH_AES_128_CBC_SHA,
		http2cipher_TLS_RSA_WITH_AES_256_CBC_SHA,
		http2cipher_TLS_DH_DSS_WITH_AES_256_CBC_SHA,
		http2cipher_TLS_DH_RSA_WITH_AES_256_CBC_SHA,
		http2cipher_TLS_DHE_DSS_WITH_AES_256_CBC_SHA,
		http2cipher_TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
		http2cipher_TLS_DH_anon_WITH_AES_256_CBC_SHA,
		http2cipher_TLS_RSA_WITH_NULL_SHA256,
		http2cipher_TLS_RSA_WITH_AES_128_CBC_SHA256,
		http2cipher_TLS_RSA_WITH_AES_256_CBC_SHA256,
		http2cipher_TLS_DH_DSS_WITH_AES_128_CBC_SHA256,
		http2cipher_TLS_DH_RSA_WITH_AES_128_CBC_SHA256,
		http2cipher_TLS_DHE_DSS_WITH_AES_128_CBC_SHA256,
		http2cipher_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA,
		http2cipher_TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA,
		http2cipher_TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA,
		http2cipher_TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA,
		http2cipher_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA,
		http2cipher_TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA,
		http2cipher_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,
		http2cipher_TLS_DH_DSS_WITH_AES_256_CBC_SHA256,
		http2cipher_TLS_DH_RSA_WITH_AES_256_CBC_SHA256,
		http2cipher_TLS_DHE_DSS_WITH_AES_256_CBC_SHA256,
		http2cipher_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,
		http2cipher_TLS_DH_anon_WITH_AES_128_CBC_SHA256,
		http2cipher_TLS_DH_anon_WITH_AES_256_CBC_SHA256,
		http2cipher_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA,
		http2cipher_TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA,
		http2cipher_TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA,
		http2cipher_TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA,
		http2cipher_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA,
		http2cipher_TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA,
		http2cipher_TLS_PSK_WITH_RC4_128_SHA,
		http2cipher_TLS_PSK_WITH_3DES_EDE_CBC_SHA,
		http2cipher_TLS_PSK_WITH_AES_128_CBC_SHA,
		http2cipher_TLS_PSK_WITH_AES_256_CBC_SHA,
		http2cipher_TLS_DHE_PSK_WITH_RC4_128_SHA,
		http2cipher_TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA,
		http2cipher_TLS_DHE_PSK_WITH_AES_128_CBC_SHA,
		http2cipher_TLS_DHE_PSK_WITH_AES_256_CBC_SHA,
		http2cipher_TLS_RSA_PSK_WITH_RC4_128_SHA,
		http2cipher_TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA,
		http2cipher_TLS_RSA_PSK_WITH_AES_128_CBC_SHA,
		http2cipher_TLS_RSA_PSK_WITH_AES_256_CBC_SHA,
		http2cipher_TLS_RSA_WITH_SEED_CBC_SHA,
		http2cipher_TLS_DH_DSS_WITH_SEED_CBC_SHA,
		http2cipher_TLS_DH_RSA_WITH_SEED_CBC_SHA,
		http2cipher_TLS_DHE_DSS_WITH_SEED_CBC_SHA,
		http2cipher_TLS_DHE_RSA_WITH_SEED_CBC_SHA,
		http2cipher_TLS_DH_anon_WITH_SEED_CBC_SHA,
		http2cipher_TLS_RSA_WITH_AES_128_GCM_SHA256,
		http2cipher_TLS_RSA_WITH_AES_256_GCM_SHA384,
		http2cipher_TLS_DH_RSA_WITH_AES_128_GCM_SHA256,
		http2cipher_TLS_DH_RSA_WITH_AES_256_GCM_SHA384,
		http2cipher_TLS_DH_DSS_WITH_AES_128_GCM_SHA256,
		http2cipher_TLS_DH_DSS_WITH_AES_256_GCM_SHA384,
		http2cipher_TLS_DH_anon_WITH_AES_128_GCM_SHA256,
		http2cipher_TLS_DH_anon_WITH_AES_256_GCM_SHA384,
		http2cipher_TLS_PSK_WITH_AES_128_GCM_SHA256,
		http2cipher_TLS_PSK_WITH_AES_256_GCM_SHA384,
		http2cipher_TLS_RSA_PSK_WITH_AES_128_GCM_SHA256,
		http2cipher_TLS_RSA_PSK_WITH_AES_256_GCM_SHA384,
		http2cipher_TLS_PSK_WITH_AES_128_CBC_SHA256,
		http2cipher_TLS_PSK_WITH_AES_256_CBC_SHA384,
		http2cipher_TLS_PSK_WITH_NULL_SHA256,
		http2cipher_TLS_PSK_WITH_NULL_SHA384,
		http2cipher_TLS_DHE_PSK_WITH_AES_128_CBC_SHA256,
		http2cipher_TLS_DHE_PSK_WITH_AES_256_CBC_SHA384,
		http2cipher_TLS_DHE_PSK_WITH_NULL_SHA256,
		http2cipher_TLS_DHE_PSK_WITH_NULL_SHA384,
		http2cipher_TLS_RSA_PSK_WITH_AES_128_CBC_SHA256,
		http2cipher_TLS_RSA_PSK_WITH_AES_256_CBC_SHA384,
		http2cipher_TLS_RSA_PSK_WITH_NULL_SHA256,
		http2cipher_TLS_RSA_PSK_WITH_NULL_SHA384,
		http2cipher_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256,
		http2cipher_TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256,
		http2cipher_TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256,
		http2cipher_TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256,
		http2cipher_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256,
		http2cipher_TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256,
		http2cipher_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256,
		http2cipher_TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256,
		http2cipher_TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256,
		http2cipher_TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256,
		http2cipher_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256,
		http2cipher_TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256,
		http2cipher_TLS_EMPTY_RENEGOTIATION_INFO_SCSV,
		http2cipher_TLS_ECDH_ECDSA_WITH_NULL_SHA,
		http2cipher_TLS_ECDH_ECDSA_WITH_RC4_128_SHA,
		http2cipher_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA,
		http2cipher_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,
		http2cipher_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA,
		http2cipher_TLS_ECDHE_ECDSA_WITH_NULL_SHA,
		http2cipher_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
		http2cipher_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,
		http2cipher_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
		http2cipher_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
		http2cipher_TLS_ECDH_RSA_WITH_NULL_SHA,
		http2cipher_TLS_ECDH_RSA_WITH_RC4_128_SHA,
		http2cipher_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA,
		http2cipher_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA,
		http2cipher_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA,
		http2cipher_TLS_ECDHE_RSA_WITH_NULL_SHA,
		http2cipher_TLS_ECDHE_RSA_WITH_RC4_128_SHA,
		http2cipher_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
		http2cipher_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
		http2cipher_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
		http2cipher_TLS_ECDH_anon_WITH_NULL_SHA,
		http2cipher_TLS_ECDH_anon_WITH_RC4_128_SHA,
		http2cipher_TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA,
		http2cipher_TLS_ECDH_anon_WITH_AES_128_CBC_SHA,
		http2cipher_TLS_ECDH_anon_WITH_AES_256_CBC_SHA,
		http2cipher_TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA,
		http2cipher_TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA,
		http2cipher_TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA,
		http2cipher_TLS_SRP_SHA_WITH_AES_128_CBC_SHA,
		http2cipher_TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA,
		http2cipher_TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA,
		http2cipher_TLS_SRP_SHA_WITH_AES_256_CBC_SHA,
		http2cipher_TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA,
		http2cipher_TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA,
		http2cipher_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
		http2cipher_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,
		http2cipher_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256,
		http2cipher_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384,
		http2cipher_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
		http2cipher_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,
		http2cipher_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256,
		http2cipher_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384,
		http2cipher_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256,
		http2cipher_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384,
		http2cipher_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256,
		http2cipher_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384,
		http2cipher_TLS_ECDHE_PSK_WITH_RC4_128_SHA,
		http2cipher_TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA,
		http2cipher_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA,
		http2cipher_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA,
		http2cipher_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256,
		http2cipher_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384,
		http2cipher_TLS_ECDHE_PSK_WITH_NULL_SHA,
		http2cipher_TLS_ECDHE_PSK_WITH_NULL_SHA256,
		http2cipher_TLS_ECDHE_PSK_WITH_NULL_SHA384,
		http2cipher_TLS_RSA_WITH_ARIA_128_CBC_SHA256,
		http2cipher_TLS_RSA_WITH_ARIA_256_CBC_SHA384,
		http2cipher_TLS_DH_DSS_WITH_ARIA_128_CBC_SHA256,
		http2cipher_TLS_DH_DSS_WITH_ARIA_256_CBC_SHA384,
		http2cipher_TLS_DH_RSA_WITH_ARIA_128_CBC_SHA256,
		http2cipher_TLS_DH_RSA_WITH_ARIA_256_CBC_SHA384,
		http2cipher_TLS_DHE_DSS_WITH_ARIA_128_CBC_SHA256,
		http2cipher_TLS_DHE_DSS_WITH_ARIA_256_CBC_SHA384,
		http2cipher_TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256,
		http2cipher_TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384,
		http2cipher_TLS_DH_anon_WITH_ARIA_128_CBC_SHA256,
		http2cipher_TLS_DH_anon_WITH_ARIA_256_CBC_SHA384,
		http2cipher_TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256,
		http2cipher_TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384,
		http2cipher_TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256,
		http2cipher_TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384,
		http2cipher_TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256,
		http2cipher_TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384,
		http2cipher_TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256,
		http2cipher_TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384,
		http2cipher_TLS_RSA_WITH_ARIA_128_GCM_SHA256,
		http2cipher_TLS_RSA_WITH_ARIA_256_GCM_SHA384,
		http2cipher_TLS_DH_RSA_WITH_ARIA_128_GCM_SHA256,
		http2cipher_TLS_DH_RSA_WITH_ARIA_256_GCM_SHA384,
		http2cipher_TLS_DH_DSS_WITH_ARIA_128_GCM_SHA256,
		http2cipher_TLS_DH_DSS_WITH_ARIA_256_GCM_SHA384,
		http2cipher_TLS_DH_anon_WITH_ARIA_128_GCM_SHA256,
		http2cipher_TLS_DH_anon_WITH_ARIA_256_GCM_SHA384,
		http2cipher_TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256,
		http2cipher_TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384,
		http2cipher_TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256,
		http2cipher_TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384,
		http2cipher_TLS_PSK_WITH_ARIA_128_CBC_SHA256,
		http2cipher_TLS_PSK_WITH_ARIA_256_CBC_SHA384,
		http2cipher_TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256,
		http2cipher_TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384,
		http2cipher_TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256,
		http2cipher_TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384,
		http2cipher_TLS_PSK_WITH_ARIA_128_GCM_SHA256,
		http2cipher_TLS_PSK_WITH_ARIA_256_GCM_SHA384,
		http2cipher_TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256,
		http2cipher_TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384,
		http2cipher_TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256,
		http2cipher_TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384,
		http2cipher_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256,
		http2cipher_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384,
		http2cipher_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256,
		http2cipher_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384,
		http2cipher_TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256,
		http2cipher_TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384,
		http2cipher_TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256,
		http2cipher_TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384,
		http2cipher_TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256,
		http2cipher_TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384,
		http2cipher_TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256,
		http2cipher_TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384,
		http2cipher_TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256,
		http2cipher_TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384,
		http2cipher_TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256,
		http2cipher_TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384,
		http2cipher_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256,
		http2cipher_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384,
		http2cipher_TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256,
		http2cipher_TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384,
		http2cipher_TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256,
		http2cipher_TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384,
		http2cipher_TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256,
		http2cipher_TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384,
		http2cipher_TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256,
		http2cipher_TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384,
		http2cipher_TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256,
		http2cipher_TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384,
		http2cipher_TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256,
		http2cipher_TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384,
		http2cipher_TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256,
		http2cipher_TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384,
		http2cipher_TLS_RSA_WITH_AES_128_CCM,
		http2cipher_TLS_RSA_WITH_AES_256_CCM,
		http2cipher_TLS_RSA_WITH_AES_128_CCM_8,
		http2cipher_TLS_RSA_WITH_AES_256_CCM_8,
		http2cipher_TLS_PSK_WITH_AES_128_CCM,
		http2cipher_TLS_PSK_WITH_AES_256_CCM,
		http2cipher_TLS_PSK_WITH_AES_128_CCM_8,
		http2cipher_TLS_PSK_WITH_AES_256_CCM_8:
		return true
	default:
		return false
	}
}

// ClientConnPool管理HTTP/2客户端连接池的密码套件。
type http2ClientConnPool interface {
	// GetClientConn返回到HTTP/2服务器的特定HTTP/2连接（通常是
	// TLS-TCP连接）。成功后，
	// 返回的ClientConn将解释即将到来的往返
	// 呼叫，因此呼叫方不应忽略它。如果来电者需要
	// to，请拨打ClientConn。可以使用伪
	// new（http.Request）调用往返，以释放流保留。
	GetClientConn(req *Request, addr string) (*http2ClientConn, error)
	MarkDead(*http2ClientConn)
}

// clientConnPoolIdleCloser是ClientConnPool 
// 实现的接口，可以关闭其空闲连接。
type http2clientConnPoolIdleCloser interface {
	http2ClientConnPool
	closeIdleConnections()
}

var (
	_ http2clientConnPoolIdleCloser = (*http2clientConnPool)(nil)
	_ http2clientConnPoolIdleCloser = http2noDialClientConnPool{}
)

// TODO:使用singleflight进行拨号和通话？
type http2clientConnPool struct {
	t *http2Transport

	mu sync.Mutex // TODO:可能会切换到RWMutex 
	// TODO:添加基于证书名共享conn的支持
	// （例如，googleapis.com和appspot.com的共享conn）
	conns        map[string][]*http2ClientConn // 密钥是主机：端口
	dialing      map[string]*http2dialCall     // 目前正在飞行中拨打
	keys         map[*http2ClientConn][]string
}

func (p *http2clientConnPool) GetClientConn(req *Request, addr string) (*http2ClientConn, error) {
	return p.getClientConn(req, addr, http2dialOnMiss)
}

const (
	http2dialOnMiss   = true
	http2noDialOnMiss = false
)

func (p *http2clientConnPool) getClientConn(req *Request, addr string, dialOnMiss bool) (*http2ClientConn, error) {
	if http2isConnectionCloseRequest(req) && dialOnMiss {
		// 它有自己的连接。
		http2traceGetConn(req, addr)
		const singleUse = true
		cc, err := p.t.dialClientConn(req.Context(), addr, singleUse)
		if err != nil {
			return nil, err
		}
		return cc, nil
	}
	for {
		p.mu.Lock()
		for _, cc := range p.conns[addr] {
			if cc.ReserveNewRequest() {
				// 当一个连接通过net/http包呈现给我们时，
				// GetConn钩子已经被调用了。
				// 这里不要再叫它了。
				if !cc.getConnCalled {
					http2traceGetConn(req, addr)
				}
				cc.getConnCalled = false
				p.mu.Unlock()
				return cc, nil
			}
		}
		if !dialOnMiss {
			p.mu.Unlock()
			return nil, http2ErrNoCachedConn
		}
		http2traceGetConn(req, addr)
		call := p.getStartDialLocked(req.Context(), addr)
		p.mu.Unlock()
		<-call.done
		if http2shouldRetryDial(call, req) {
			continue
		}
		cc, err := call.res, call.err
		if err != nil {
			return nil, err
		}
		if cc.ReserveNewRequest() {
			return cc, nil
		}
	}
}

// dialCall是对主机的机内传输拨号呼叫。
type http2dialCall struct {
	_ http2incomparable
	p *http2clientConnPool
	// 与创建此拨号呼叫的请求
	// 关联的上下文
	ctx  context.Context
	done chan struct{}    // 完成时关闭
	res  *http2ClientConn // 完成后有效
	err  error            // 完成后有效
}

// 需要保留p.mu。
func (p *http2clientConnPool) getStartDialLocked(ctx context.Context, addr string) *http2dialCall {
	if call, ok := p.dialing[addr]; ok {
		// 一个拨号盘已经在运行中。不要开始另一个。
		return call
	}
	call := &http2dialCall{p: p, done: make(chan struct{}), ctx: ctx}
	if p.dialing == nil {
		p.dialing = make(map[string]*http2dialCall)
	}
	p.dialing[addr] = call
	go call.dial(call.ctx, addr)
	return call
}

// 在自己的goroutine中运行。
func (c *http2dialCall) dial(ctx context.Context, addr string) {
	const singleUse = false // 共享连接
	c.res, c.err = c.p.t.dialClientConn(ctx, addr, singleUse)
	close(c.done)

	c.p.mu.Lock()
	delete(c.p.dialing, addr)
	if c.err == nil {
		c.p.addConnLocked(addr, c.res)
	}
	c.p.mu.Unlock()
}

// 如果密钥的连接不存在，addConnIfNeeded将用c生成一个新的客户端连接。它使用相同的键合并并发调用。
// 这是http1传输代码在创建新连接时使用的。因为http1传输不将TCP拨号重复数据消除到出站主机（因为它不知道协议），所以它可能会遇到有多个TLS连接的情况。
// 此代码决定哪些人生存或死亡。
// 使用的返回值是是否使用了c。
// c永远不会关闭。
func (p *http2clientConnPool) addConnIfNeeded(key string, t *http2Transport, c *tls.Conn) (used bool, err error) {
	p.mu.Lock()
	for _, cc := range p.conns[key] {
		if cc.CanTakeNewRequest() {
			p.mu.Unlock()
			return false, nil
		}
	}
	call, dup := p.addConnCalls[key]
	if !dup {
		if p.addConnCalls == nil {
			p.addConnCalls = make(map[string]*http2addConnCall)
		}
		call = &http2addConnCall{
			p:    p,
			done: make(chan struct{}),
		}
		p.addConnCalls[key] = call
		go call.run(t, key, c)
	}
	p.mu.Unlock()

	<-call.done
	if call.err != nil {
		return false, call.err
	}
	return !dup, nil
}

type http2addConnCall struct {
	_    http2incomparable
	p    *http2clientConnPool
	done chan struct{} // 完成后关闭
	err  error
}

func (c *http2addConnCall) run(t *http2Transport, key string, tc *tls.Conn) {
	cc, err := t.NewClientConn(tc)

	p := c.p
	p.mu.Lock()
	if err != nil {
		c.err = err
	} else {
		cc.getConnCalled = true // 已被net/http包调用
		p.addConnLocked(key, cc)
	}
	delete(p.addConnCalls, key)
	p.mu.Unlock()
	close(c.done)
}

// 必须持有p.mu 
func (p *http2clientConnPool) addConnLocked(key string, cc *http2ClientConn) {
	for _, v := range p.conns[key] {
		if v == cc {
			return
		}
	}
	if p.conns == nil {
		p.conns = make(map[string][]*http2ClientConn)
	}
	if p.keys == nil {
		p.keys = make(map[*http2ClientConn][]string)
	}
	p.conns[key] = append(p.conns[key], cc)
	p.keys[cc] = append(p.keys[cc], key)
}

func (p *http2clientConnPool) MarkDead(cc *http2ClientConn) {
	p.mu.Lock()
	defer p.mu.Unlock()
	for _, key := range p.keys[cc] {
		vv, ok := p.conns[key]
		if !ok {
			continue
		}
		newList := http2filterOutClientConn(vv, cc)
		if len(newList) > 0 {
			p.conns[key] = newList
		} else {
			delete(p.conns, key)
		}
	}
	delete(p.keys, cc)
}

func (p *http2clientConnPool) closeIdleConnections() {
	p.mu.Lock()
	defer p.mu.Unlock()
	// TODO:如果cc在几毫秒前刚刚添加到池
	// 并且从未使用过，请不要关闭cc。目前有一个与HTTP/1传输集成的小型竞争窗口，可以在使用前添加一个空闲连接，其他人可以同时调用CloseIdlecons和
	// 中断某个调用方的往返。
	for _, vv := range p.conns {
		for _, cc := range vv {
			cc.closeIfIdle()
		}
	}
}

func http2filterOutClientConn(in []*http2ClientConn, exclude *http2ClientConn) []*http2ClientConn {
	out := in[:0]
	for _, v := range in {
		if v != exclude {
			out = append(out, v)
		}
	}
	// 如果我们过滤掉它，将最后一项归零，以防止GC看到它。
	if len(in) != len(out) {
		in[len(in)-1] = nil
	}
	return out
}

// noDialClientConnPool是http2的一个实现。ClientConnPool 
// 从不拨号。我们让HTTP/1.1客户端拨号并使用其TLS 
// 连接。
type http2noDialClientConnPool struct{ *http2clientConnPool }

func (p http2noDialClientConnPool) GetClientConn(req *Request, addr string) (*http2ClientConn, error) {
	return p.getClientConn(req, addr, http2noDialOnMiss)
}

// shouldreydial报告当前请求是否应
// 在呼叫失败后重试拨号，例如
// 如果由于上下文取消或
// 截止日期到期而取消拨号。
func http2shouldRetryDial(call *http2dialCall, req *Request) bool {
	if call.err == nil {
		// 无错误，无需重试
		return false
	}
	if call.ctx == req.Context() {
		// 如果呼叫与请求具有相同的上下文，则不应重试拨号
		// 因为任何取消都将来自此请求。
		return false
	}
	if !errors.Is(call.err, context.Canceled) && !errors.Is(call.err, context.DeadlineExceeded) {
		// 如果呼叫错误不是因为上下文取消或截止日期到期，
		// 不应重试拨号。
		return false
	}
	// 仅当错误是上下文取消错误或截止日期到期时重试
	// 并且与调用关联的上下文已被取消或到期。
	return call.ctx.Err() != nil
}

// 缓冲区块是从池中分配的，以减轻GC的压力。
// 每个数据缓冲区的最大浪费空间是最大大小类的2倍，
// 当数据缓冲区有多个块，并且第一个和最后一个块中都有一个未读字节时，就会发生这种情况。我们使用几个大小的
// 类来最小化通常接收非常
// 小请求体的服务器的开销。
// 
// TODO:确定池是否必要的基准测试。GC可能已经改进了
// 我们可以这样分配块：
// make（[]字节，最大值（16<<10，expectedbytes剩余值））
var (
	http2dataChunkSizeClasses = []int{
		1 << 10,
		2 << 10,
		4 << 10,
		8 << 10,
		16 << 10,
	}
	http2dataChunkPools = [...]sync.Pool{
		{New: func() interface{} { return make([]byte, 1<<10) }},
		{New: func() interface{} { return make([]byte, 2<<10) }},
		{New: func() interface{} { return make([]byte, 4<<10) }},
		{New: func() interface{} { return make([]byte, 8<<10) }},
		{New: func() interface{} { return make([]byte, 16<<10) }},
	}
)

func http2getDataBufferChunk(size int64) []byte {
	i := 0
	for ; i < len(http2dataChunkSizeClasses)-1; i++ {
		if size <= int64(http2dataChunkSizeClasses[i]) {
			break
		}
	}
	return http2dataChunkPools[i].Get().([]byte)
}

func http2putDataBufferChunk(p []byte) {
	for i, n := range http2dataChunkSizeClasses {
		if len(p) == n {
			http2dataChunkPools[i].Put(p)
			return
		}
	}
	panic(fmt.Sprintf("unexpected buffer len=%v", len(p)))
}

// 数据缓冲是一个io。ReadWriter由一系列数据块支持。
// 每个数据缓冲区用于读取单个流上的数据帧。
// 缓冲区被分为块，这样服务器就可以限制单个连接使用的总内存，而不限制任何单个流上的
// 请求正文大小。
type http2dataBuffer struct {
	chunks   [][]byte
	r        int   // 下一个要读取的字节是块[0][r]
	w        int   // 下一个要写入的字节是块[len（chunks）-1][w]
	size     int   // 总缓冲字节数
	expected int64 // 我们预计在未来的写调用中至少会有这么多字节（如果<=0则忽略）
}

var http2errReadEmpty = errors.New("read from empty dataBuffer")

// 将字节从缓冲区中读取到p中。
// 没有数据时读取是错误的可获得的
func (b *http2dataBuffer) Read(p []byte) (int, error) {
	if b.size == 0 {
		return 0, http2errReadEmpty
	}
	var ntotal int
	for len(p) > 0 && b.size > 0 {
		readFrom := b.bytesFromFirstChunk()
		n := copy(p, readFrom)
		p = p[n:]
		ntotal += n
		b.r += n
		b.size -= n
		// 如果第一个区块已被消耗，则前进到下一个区块。
		if b.r == len(b.chunks[0]) {
			http2putDataBufferChunk(b.chunks[0])
			end := len(b.chunks) - 1
			copy(b.chunks[:end], b.chunks[1:])
			b.chunks[end] = nil
			b.chunks = b.chunks[:end]
			b.r = 0
		}
	}
	return ntotal, nil
}

func (b *http2dataBuffer) bytesFromFirstChunk() []byte {
	if len(b.chunks) == 1 {
		return b.chunks[0][b.r:b.w]
	}
	return b.chunks[0][b.r:]
}

// Len返回缓冲区未读部分的字节数。
func (b *http2dataBuffer) Len() int {
	return b.size
}

// Write将p追加到缓冲区。
func (b *http2dataBuffer) Write(p []byte) (int, error) {
	ntotal := len(p)
	for len(p) > 0 {
		// 如果最后一个区块为空，则分配一个新区块。尝试分配足够的
		// 以完全复制p加上我们希望
		// 接收的任何额外字节。然而，这可能会分配少于len（p）。
		want := int64(len(p))
		if b.expected > want {
			want = b.expected
		}
		chunk := b.lastChunkOrAlloc(want)
		n := copy(chunk[b.w:], p)
		p = p[n:]
		b.w += n
		b.size += n
		b.expected -= int64(n)
	}
	return ntotal, nil
}

func (b *http2dataBuffer) lastChunkOrAlloc(want int64) []byte {
	if len(b.chunks) != 0 {
		last := b.chunks[len(b.chunks)-1]
		if b.w < len(last) {
			return last
		}
	}
	chunk := http2getDataBufferChunk(want)
	b.chunks = append(b.chunks, chunk)
	b.w = 0
	return chunk
}

// 错误代码是HTTP/2规范中定义的无符号32位错误代码。
type http2ErrCode uint32

const (
	http2ErrCodeNo                 http2ErrCode = 0x0
	http2ErrCodeProtocol           http2ErrCode = 0x1
	http2ErrCodeInternal           http2ErrCode = 0x2
	http2ErrCodeFlowControl        http2ErrCode = 0x3
	http2ErrCodeSettingsTimeout    http2ErrCode = 0x4
	http2ErrCodeStreamClosed       http2ErrCode = 0x5
	http2ErrCodeFrameSize          http2ErrCode = 0x6
	http2ErrCodeRefusedStream      http2ErrCode = 0x7
	http2ErrCodeCancel             http2ErrCode = 0x8
	http2ErrCodeCompression        http2ErrCode = 0x9
	http2ErrCodeConnect            http2ErrCode = 0xa
	http2ErrCodeEnhanceYourCalm    http2ErrCode = 0xb
	http2ErrCodeInadequateSecurity http2ErrCode = 0xc
	http2ErrCodeHTTP11Required     http2ErrCode = 0xd
)

var http2errCodeName = map[http2ErrCode]string{
	http2ErrCodeNo:                 "NO_ERROR",
	http2ErrCodeProtocol:           "PROTOCOL_ERROR",
	http2ErrCodeInternal:           "INTERNAL_ERROR",
	http2ErrCodeFlowControl:        "FLOW_CONTROL_ERROR",
	http2ErrCodeSettingsTimeout:    "SETTINGS_TIMEOUT",
	http2ErrCodeStreamClosed:       "STREAM_CLOSED",
	http2ErrCodeFrameSize:          "FRAME_SIZE_ERROR",
	http2ErrCodeRefusedStream:      "REFUSED_STREAM",
	http2ErrCodeCancel:             "CANCEL",
	http2ErrCodeCompression:        "COMPRESSION_ERROR",
	http2ErrCodeConnect:            "CONNECT_ERROR",
	http2ErrCodeEnhanceYourCalm:    "ENHANCE_YOUR_CALM",
	http2ErrCodeInadequateSecurity: "INADEQUATE_SECURITY",
	http2ErrCodeHTTP11Required:     "HTTP_1_1_REQUIRED",
}

func (e http2ErrCode) String() string {
	if s, ok := http2errCodeName[e]; ok {
		return s
	}
	return fmt.Sprintf("unknown error code 0x%x", uint32(e))
}

func (e http2ErrCode) stringToken() string {
	if s, ok := http2errCodeName[e]; ok {
		return s
	}
	return fmt.Sprintf("ERR_UNKNOWN_%d", uint32(e))
}

// ConnectionError是导致整个连接终止的错误。
type http2ConnectionError http2ErrCode

func (e http2ConnectionError) Error() string {
	return fmt.Sprintf("connection error: %s", http2ErrCode(e))
}

// StreamError是一个错误，它只影响
// HTTP/2连接中的一个流。
type http2StreamError struct {
	StreamID uint32
	Code     http2ErrCode
	Cause    error // 可选附加详细信息
}

// errFromPeer是StreamError的一个前哨错误值。导致
// 表示拖缆错误是通过导线
// 从对等方发送的，并且不是在传输中本地生成的。
var http2errFromPeer = errors.New("received from peer")

func http2streamError(id uint32, code http2ErrCode) http2StreamError {
	return http2StreamError{StreamID: id, Code: code}
}

func (e http2StreamError) Error() string {
	if e.Cause != nil {
		return fmt.Sprintf("stream error: stream ID %d; %v; %v", e.StreamID, e.Code, e.Cause)
	}
	return fmt.Sprintf("stream error: stream ID %d; %v", e.StreamID, e.Code)
}

// 6.9.1流控制窗口
// “如果发送方收到导致流控制
// 窗口超过此最大值的窗口更新，则必须终止流
// 或连接，视情况而定。对于流，[…]；对于
// 连接，一个带有流控制错误代码的GOAWAY帧。“
type http2goAwayFlowError struct{}

func (http2goAwayFlowError) Error() string { return "connection exceeded flow control window size" }

// connError表示一个HTTP/2 ConnectionError错误代码，以及
// 带有一个字符串（用于调试）来解释原因。
// 
// 这种类型的错误仅由帧分析器函数
// 返回并转换为ConnectionError（代码），将原因隐藏到制宪者的errDetail字段中后，可通过
// 制宪者（*Framer）访问。ErrorDetail方法。
type http2connError struct {
	Code   http2ErrCode // 连接错误代码
	Reason string       // 其他原因
}

func (e http2connError) Error() string {
	return fmt.Sprintf("http2: connection error: %v: %v", e.Code, e.Reason)
}

type http2pseudoHeaderError string

func (e http2pseudoHeaderError) Error() string {
	return fmt.Sprintf("invalid pseudo-header %q", string(e))
}

type http2duplicatePseudoHeaderError string

func (e http2duplicatePseudoHeaderError) Error() string {
	return fmt.Sprintf("duplicate pseudo-header %q", string(e))
}

type http2headerFieldNameError string

func (e http2headerFieldNameError) Error() string {
	return fmt.Sprintf("invalid header field name %q", string(e))
}

type http2headerFieldValueError string

func (e http2headerFieldValueError) Error() string {
	return fmt.Sprintf("invalid header field value %q", string(e))
}

var (
	http2errMixPseudoHeaderTypes = errors.New("mix of request and response pseudo headers")
	http2errPseudoAfterRegular   = errors.New("pseudo header field after regular")
)

// 流量是流量控制窗口的大小。
type http2flow struct {
	_ http2incomparable

	// n是允许发送的数据字节数。
	// 一个流同时保存在conn和per流上。
	n int32

	// conn指向共享连接级别的流，该流由该conn上的所有流共享。直接位于conn上的流
	// 为零。
	conn *http2flow
}

func (f *http2flow) setConnFlow(cf *http2flow) { f.conn = cf }

func (f *http2flow) available() int32 {
	n := f.n
	if f.conn != nil && f.conn.n < n {
		n = f.conn.n
	}
	return n
}

func (f *http2flow) take(n int32) {
	if n > f.available() {
		panic("internal error: took too much")
	}
	f.n -= n
	if f.conn != nil {
		f.conn.n -= n
	}
}

// add将n个字节（正或负）添加到流控制窗口。
// 如果总和超过2^31-1，则返回false。
func (f *http2flow) add(n int32) bool {
	sum := f.n + n
	if (sum > n) == (f.n > 0) {
		f.n = sum
		return true
	}
	return false
}

const http2frameHeaderLen = 9

var http2padZeros = make([]byte, 255) // 填充零

// 帧类型是在
// http2.github.io/http2-spec/#rfc.section.11.2
type http2FrameType uint8

const (
	http2FrameData         http2FrameType = 0x0
	http2FrameHeaders      http2FrameType = 0x1
	http2FramePriority     http2FrameType = 0x2
	http2FrameRSTStream    http2FrameType = 0x3
	http2FrameSettings     http2FrameType = 0x4
	http2FramePushPromise  http2FrameType = 0x5
	http2FramePing         http2FrameType = 0x6
	http2FrameGoAway       http2FrameType = 0x7
	http2FrameWindowUpdate http2FrameType = 0x8
	http2FrameContinuation http2FrameType = 0x9
)

var http2frameName = map[http2FrameType]string{
	http2FrameData:         "DATA",
	http2FrameHeaders:      "HEADERS",
	http2FramePriority:     "PRIORITY",
	http2FrameRSTStream:    "RST_STREAM",
	http2FrameSettings:     "SETTINGS",
	http2FramePushPromise:  "PUSH_PROMISE",
	http2FramePing:         "PING",
	http2FrameGoAway:       "GOAWAY",
	http2FrameWindowUpdate: "WINDOW_UPDATE",
	http2FrameContinuation: "CONTINUATION",
}

func (t http2FrameType) String() string {
	if s, ok := http2frameName[t]; ok {
		return s
	}
	return fmt.Sprintf("UNKNOWN_FRAME_TYPE_%d", uint8(t))
}

// 标志是HTTP/2标志的位掩码。
// 标志的含义因帧类型而异。
type http2Flags uint8

// 报告f是否在v中包含所有（0或更多）标志。
func (f http2Flags) Has(v http2Flags) bool {
	return (f & v) == v
}

// 特定于帧的帧头标志位。
const (
	// 数据帧
	http2FlagDataEndStream http2Flags = 0x1
	http2FlagDataPadded    http2Flags = 0x8

	// 头帧
	http2FlagHeadersEndStream  http2Flags = 0x1
	http2FlagHeadersEndHeaders http2Flags = 0x4
	http2FlagHeadersPadded     http2Flags = 0x8
	http2FlagHeadersPriority   http2Flags = 0x20

	// 设置帧
	http2FlagSettingsAck http2Flags = 0x1

	// Ping帧
	http2FlagPingAck http2Flags = 0x1

	// 延续帧
	http2FlagContinuationEndHeaders http2Flags = 0x4

	http2FlagPushPromiseEndHeaders http2Flags = 0x4
	http2FlagPushPromisePadded     http2Flags = 0x8
)

var http2flagName = map[http2FrameType]map[http2Flags]string{
	http2FrameData: {
		http2FlagDataEndStream: "END_STREAM",
		http2FlagDataPadded:    "PADDED",
	},
	http2FrameHeaders: {
		http2FlagHeadersEndStream:  "END_STREAM",
		http2FlagHeadersEndHeaders: "END_HEADERS",
		http2FlagHeadersPadded:     "PADDED",
		http2FlagHeadersPriority:   "PRIORITY",
	},
	http2FrameSettings: {
		http2FlagSettingsAck: "ACK",
	},
	http2FramePing: {
		http2FlagPingAck: "ACK",
	},
	http2FrameContinuation: {
		http2FlagContinuationEndHeaders: "END_HEADERS",
	},
	http2FramePushPromise: {
		http2FlagPushPromiseEndHeaders: "END_HEADERS",
		http2FlagPushPromisePadded:     "PADDED",
	},
}

// 帧解析器解析给定帧头和有效负载的帧
// 字节。有效载荷的长度始终等于fh。长度（
// 可能是0）。
type http2frameParser func(fc *http2frameCache, fh http2FrameHeader, countError func(string), payload []byte) (http2Frame, error)

var http2frameParsers = map[http2FrameType]http2frameParser{
	http2FrameData:         http2parseDataFrame,
	http2FrameHeaders:      http2parseHeadersFrame,
	http2FramePriority:     http2parsePriorityFrame,
	http2FrameRSTStream:    http2parseRSTStreamFrame,
	http2FrameSettings:     http2parseSettingsFrame,
	http2FramePushPromise:  http2parsePushPromise,
	http2FramePing:         http2parsePingFrame,
	http2FrameGoAway:       http2parseGoAwayFrame,
	http2FrameWindowUpdate: http2parseWindowUpdateFrame,
	http2FrameContinuation: http2parseContinuationFrame,
}

func http2typeFrameParser(t http2FrameType) http2frameParser {
	if f := http2frameParsers[t]; f != nil {
		return f
	}
	return http2parseUnknownFrame
}

// 帧头是所有HTTP/2帧的9字节头。
// 参见http:
type http2FrameHeader struct {
	valid bool // 调用者可以访问帧中的[]字节字段

	// 类型是1字节的帧类型。有十种标准帧
	// 类型，但扩展帧类型可能由writerWorkFrame 
	// 编写，并将由ReadFrame返回（作为未知帧）。
	Type http2FrameType

	// 标志是每帧8个潜在位标志的1字节。
	// 它们特定于框架类型。
	Flags http2Flags

	// 长度是帧的长度，不包括9字节的头。
	// 最大大小为小于16MB的一个字节（uint24），但在没有对等协议的情况下，只允许最大为16KB的帧。
	Length uint32

	// StreamID是此帧用于哪个流。某些帧
	// 不是特定于流的，在这种情况下，该字段为0。
	StreamID uint32
}

// Header返回h。它的存在是为了使FrameHeader可以嵌入到其他
// 特定的帧类型中，并实现帧接口。
func (h http2FrameHeader) Header() http2FrameHeader { return h }

func (h http2FrameHeader) String() string {
	var buf bytes.Buffer
	buf.WriteString("[FrameHeader ")
	h.writeDebug(&buf)
	buf.WriteByte(']')
	return buf.String()
}

func (h http2FrameHeader) writeDebug(buf *bytes.Buffer) {
	buf.WriteString(h.Type.String())
	if h.Flags != 0 {
		buf.WriteString(" flags=")
		set := 0
		for i := uint8(0); i < 8; i++ {
			if h.Flags&(1<<i) == 0 {
				continue
			}
			set++
			if set > 1 {
				buf.WriteByte('|')
			}
			name := http2flagName[h.Type][http2Flags(1<<i)]
			if name != "" {
				buf.WriteString(name)
			} else {
				fmt.Fprintf(buf, "0x%x", 1<<i)
			}
		}
	}
	if h.StreamID != 0 {
		fmt.Fprintf(buf, " stream=%d", h.StreamID)
	}
	fmt.Fprintf(buf, " len=%d", h.Length)
}

func (h *http2FrameHeader) checkValid() {
	if !h.valid {
		panic("Frame accessor called on non-owned Frame")
	}
}

func (h *http2FrameHeader) invalidate() { h.valid = false }

// 帧头字节。wen jian defg
var http2fhBytes = sync.Pool{
	New: func() interface{} {
		buf := make([]byte, http2frameHeaderLen)
		return &buf
	},
}

// ReadFrameHeader从r读取9个字节并返回一个FrameHeader。
// 大多数用户应该使用Framer。改为ReadFrame。
func http2ReadFrameHeader(r io.Reader) (http2FrameHeader, error) {
	bufp := http2fhBytes.Get().(*[]byte)
	defer http2fhBytes.Put(bufp)
	return http2readFrameHeader(*bufp, r)
}

func http2readFrameHeader(buf []byte, r io.Reader) (http2FrameHeader, error) {
	_, err := io.ReadFull(r, buf[:http2frameHeaderLen])
	if err != nil {
		return http2FrameHeader{}, err
	}
	return http2FrameHeader{
		Length:   (uint32(buf[0])<<16 | uint32(buf[1])<<8 | uint32(buf[2])),
		Type:     http2FrameType(buf[3]),
		Flags:    http2Flags(buf[4]),
		StreamID: binary.BigEndian.Uint32(buf[5:]) & (1<<31 - 1),
		valid:    true,
	}, nil
}

// 帧是所有帧类型实现的基本接口。
// 调用方通常会键入并断言特定的帧类型：
// /*HeadersFrame、*SettingsFrame、*WindowUpdateName等。
// 
// 帧仅在下次调用Framer之前有效。读框。
type http2Frame interface {
	Header() http2FrameHeader

	// invalidate由Framer调用。ReadFrame使此
	// 帧的缓冲区无效，因为后续
	// 帧将重用它们。
	invalidate()
}

// 编帧程序读取和写入帧。
type http2Framer struct {
	r         io.Reader
	lastFrame http2Frame
	errDetail error

	// countError是一个非nil函数，在帧解析时调用。
	// error带有一些唯一的错误路径标记。它是从Transport初始化的
	// 。计数器或服务器。反罗。
	countError func(errToken string)

	// 如果最后一帧是
	// 未完成的标题/继续，则lastHeaderStream为非零。
	lastHeaderStream uint32

	maxReadSize uint32
	headerBuf   [http2frameHeaderLen]byte

	// TODO:让getReadBuf可配置，并使用更少的内存固定
	// 服务器中的分配器。转到最小化多个空闲连接的固定内存。
	// 可能还需要使框架失效也有一个挂钩。
	getReadBuf func(size uint32) []byte
	readBuf    []byte // 默认getReadBuf的缓存

	maxWriteSize uint32 // 零表示无限制；TODO:Implementation 

	w    io.Writer
	wbuf []byte

	// AllowIllegalWrites允许编帧器的写入方法写入不符合HTTP/2规范的帧。此
	// 允许使用编帧器测试其他HTTP/2 
	// 实现是否符合规范。
	// 如果为false，Write方法更愿意返回错误
	// 而不是遵从。
	AllowIllegalWrites bool

	// AllowIllegalReads允许编帧者的ReadFrame方法
	// 返回不符合要求的帧或帧顺序。
	// 这是用于测试的，允许使用Framer来测试
	// 其他HTTP/2实现是否符合规范。
	// 它与ReadMetaHeaders不兼容。
	AllowIllegalReads bool

	// 如果非nil导致ReadFrame将
	// 标头和继续帧合并在一起，并返回
	// MetaHeadersFrame。
	ReadMetaHeaders *hpack.Decoder

	// MaxHeaderListSize是http2的最大页眉列表大小。
	// 仅当设置了ReadMetaHeaders时使用；0表示正常默认
	// （当前为16MB）
	// 如果达到限制，MetaHeaderFrame。截断设置为真。
	MaxHeaderListSize uint32

	// TODO:跟踪发送的帧类型和标志
	// 最后一次。然后返回一个错误（除非允许非法写入），如果ABCFDG 

	logReads, logWrites bool

	debugFramer       *http2Framer // 仅用于记录写入的操作
	debugFramerBuf    *bytes.Buffer
	debugReadLoggerf  func(string, ...interface{})
	debugWriteLoggerf func(string, ...interface{})

	frameCache *http2frameCache // 如果帧未被重用，则为零（默认值）
}

func (fr *http2Framer) maxHeaderListSize() uint32 {
	if fr.MaxHeaderListSize == 0 {
		return 16 << 20 // 根据文档
	}
	return fr.MaxHeaderListSize
}

func (f *http2Framer) startWrite(ftype http2FrameType, flags http2Flags, streamID uint32) {
	// 写入帧头，默认值为sane。
	f.wbuf = append(f.wbuf[:0],
		0, // 3字节的长度，在endWrite中填写
		0,
		0,
		byte(ftype),
		byte(flags),
		byte(streamID>>24),
		byte(streamID>>16),
		byte(streamID>>8),
		byte(streamID))
}

func (f *http2Framer) endWrite() error {
	// 现在我们知道了最终的大小，在
	// 中填写FrameHeader之前为其保留的空间。虐待。
	length := len(f.wbuf) - http2frameHeaderLen
	if length >= (1 << 24) {
		return http2ErrFrameTooLarge
	}
	_ = append(f.wbuf[:0],
		byte(length>>16),
		byte(length>>8),
		byte(length))
	if f.logWrites {
		f.logWrite()
	}

	n, err := f.w.Write(f.wbuf)
	if err == nil && n != len(f.wbuf) {
		err = io.ErrShortWrite
	}
	return err
}

func (f *http2Framer) logWrite() {
	if f.debugFramer == nil {
		f.debugFramerBuf = new(bytes.Buffer)
		f.debugFramer = http2NewFramer(nil, f.debugFramerBuf)
		f.debugFramer.logReads = false // 我们自己记录，在下面说“写”
		// 让我们读任何东西，即使我们不小心写了
		// 顺序错误：
		f.debugFramer.AllowIllegalReads = true
	}
	f.debugFramerBuf.Write(f.wbuf)
	fr, err := f.debugFramer.ReadFrame()
	if err != nil {
		f.debugWriteLoggerf("http2: Framer %p: failed to decode just-written frame", f)
		return
	}
	f.debugWriteLoggerf("http2: Framer %p: wrote %v", f, http2summarizeFrame(fr))
}

func (f *http2Framer) writeByte(v byte) { f.wbuf = append(f.wbuf, v) }

func (f *http2Framer) writeBytes(v []byte) { f.wbuf = append(f.wbuf, v...) }

func (f *http2Framer) writeUint16(v uint16) { f.wbuf = append(f.wbuf, byte(v>>8), byte(v)) }

func (f *http2Framer) writeUint32(v uint32) {
	f.wbuf = append(f.wbuf, byte(v>>24), byte(v>>16), byte(v>>8), byte(v))
}

const (
	http2minMaxFrameSize = 1 << 14
	http2maxFrameSize    = 1<<24 - 1
)

// SetReuseFrames允许框架开发者重用框架。
// 如果在成帧器上调用，则对ReadFrame的调用返回的帧只有
// 在下次调用ReadFrame之前有效。
func (fr *http2Framer) SetReuseFrames() {
	if fr.frameCache != nil {
		return
	}
	fr.frameCache = &http2frameCache{}
}

type http2frameCache struct {
	dataFrame http2DataFrame
}

func (fc *http2frameCache) getDataFrame() *http2DataFrame {
	if fc == nil {
		return &http2DataFrame{}
	}
	return &fc.dataFrame
}

// NewFramer返回一个将帧写入w并从r中读取帧的帧程序。
func http2NewFramer(w io.Writer, r io.Reader) *http2Framer {
	fr := &http2Framer{
		w:                 w,
		r:                 r,
		countError:        func(string) {},
		logReads:          http2logFrameReads,
		logWrites:         http2logFrameWrites,
		debugReadLoggerf:  log.Printf,
		debugWriteLoggerf: log.Printf,
	}
	fr.getReadBuf = func(size uint32) []byte {
		if cap(fr.readBuf) >= int(size) {
			return fr.readBuf[:size]
		}
		fr.readBuf = make([]byte, size)
		return fr.readBuf
	}
	fr.SetMaxReadFrameSize(http2maxFrameSize)
	return fr
}

// SetMaxReadFrameSize设置帧的最大大小
// 该帧将由后续的ReadFrame调用读取。
// 呼叫方有责任使用设置框宣传此
// 限制。
func (fr *http2Framer) SetMaxReadFrameSize(v uint32) {
	if v > http2maxFrameSize {
		v = http2maxFrameSize
	}
	fr.maxReadSize = v
}

// ErrorDetail返回Framer返回的上一个错误的更详细错误
// 。读框。例如，如果ReadFrame 
// 返回一个带有代码协议_错误的拖缆错误，ErrorDetail 
// 将准确说明无效内容。ErrorDetail不保证
// 返回非零值，与http2包的其他部分一样，
// 其返回值不受API兼容性承诺的保护。
// ErrorDetail在下一次调用ReadFrame后重置。
func (fr *http2Framer) ErrorDetail() error {
	return fr.errDetail
}

// ErrFrameTooLarge从成帧器返回。ReadFrame当对等
// 发送的帧大于用SetMaxReadFrameSize声明的帧时。
var http2ErrFrameTooLarge = errors.New("http2: frame too large")

// terminalReadFrameError报告err是否是不可恢复的
// 来自ReadFrame的错误，不应读取其他帧。
func http2terminalReadFrameError(err error) bool {
	if _, ok := err.(http2StreamError); ok {
		return false
	}
	return err != nil
}

// ReadFrame读取单个帧。返回的帧仅在下次调用ReadFrame之前有效。
// 
// 如果帧大于之前使用SetMaxReadFrameSize设置的帧，则返回的错误为ErrFrameTooLarge。其他错误可能是
// ConnectionError、StreamError类型，或来自基础
// 读卡器的任何其他错误。
func (fr *http2Framer) ReadFrame() (http2Frame, error) {
	fr.errDetail = nil
	if fr.lastFrame != nil {
		fr.lastFrame.invalidate()
	}
	fh, err := http2readFrameHeader(fr.headerBuf[:], fr.r)
	if err != nil {
		return nil, err
	}
	if fh.Length > fr.maxReadSize {
		return nil, http2ErrFrameTooLarge
	}
	payload := fr.getReadBuf(fh.Length)
	if _, err := io.ReadFull(fr.r, payload); err != nil {
		return nil, err
	}
	f, err := http2typeFrameParser(fh.Type)(fr.frameCache, fh, fr.countError, payload)
	if err != nil {
		if ce, ok := err.(http2connError); ok {
			return nil, fr.connError(ce.Code, ce.Reason)
		}
		return nil, err
	}
	if err := fr.checkFrameOrder(f); err != nil {
		return nil, err
	}
	if fr.logReads {
		fr.debugReadLoggerf("http2: Framer %p: read %v", fr, http2summarizeFrame(f))
	}
	if fh.Type == http2FrameHeaders && fr.ReadMetaHeaders != nil {
		return fr.readMetaFrame(f.(*http2HeadersFrame))
	}
	return f, nil
}

// connError返回ConnectionError（代码），但首先
// 隐藏了一个公开的原因，调用方可以选择在挂断前将其转发给对等方。这可能会帮助其他人调试
// 他们的实现。
func (fr *http2Framer) connError(code http2ErrCode, reason string) error {
	fr.errDetail = errors.New(reason)
	return http2ConnectionError(code)
}

// checkFrameOrder报告错误，如果f是无效的帧，则返回
// next from ReadFrame。它主要检查头和
// 连续帧是否连续。
func (fr *http2Framer) checkFrameOrder(f http2Frame) error {
	last := fr.lastFrame
	fr.lastFrame = f
	if fr.AllowIllegalReads {
		return nil
	}

	fh := f.Header()
	if fr.lastHeaderStream != 0 {
		if fh.Type != http2FrameContinuation {
			return fr.connError(http2ErrCodeProtocol,
				fmt.Sprintf("got %s for stream %d; expected CONTINUATION following %s for stream %d",
					fh.Type, fh.StreamID,
					last.Header().Type, fr.lastHeaderStream))
		}
		if fh.StreamID != fr.lastHeaderStream {
			return fr.connError(http2ErrCodeProtocol,
				fmt.Sprintf("got CONTINUATION for stream %d; expected stream %d",
					fh.StreamID, fr.lastHeaderStream))
		}
	} else if fh.Type == http2FrameContinuation {
		return fr.connError(http2ErrCodeProtocol, fmt.Sprintf("unexpected CONTINUATION for stream %d", fh.StreamID))
	}

	switch fh.Type {
	case http2FrameHeaders, http2FrameContinuation:
		if fh.Flags.Has(http2FlagHeadersEndHeaders) {
			fr.lastHeaderStream = 0
		} else {
			fr.lastHeaderStream = fh.StreamID
		}
	}

	return nil
}

// 数据帧传输与流相关的任意可变长度八位字节序列
// 数据帧。
// 参见http:
type http2DataFrame struct {
	http2FrameHeader
	data []byte
}

func (f *http2DataFrame) StreamEnded() bool {
	return f.http2FrameHeader.Flags.Has(http2FlagDataEndStream)
}

// 数据返回帧的数据八位字节，不包括任何填充
// 大小字节或填充后缀字节。
// 调用者不得在下一次
// 调用ReadFrame后保留返回的内存。
func (f *http2DataFrame) Data() []byte {
	f.checkValid()
	return f.data
}

func http2parseDataFrame(fc *http2frameCache, fh http2FrameHeader, countError func(string), payload []byte) (http2Frame, error) {
	if fh.StreamID == 0 {
		// 数据帧必须与流相关联。如果接收到流标识符为0x0的
		// 数据帧，接收方必须以
		// 连接错误（第5.4.1节）进行响应，类型为
		// 协议错误。
		countError("frame_data_stream_0")
		return nil, http2connError{http2ErrCodeProtocol, "DATA frame with stream ID 0"}
	}
	f := fc.getDataFrame()
	f.http2FrameHeader = fh

	var padSize byte
	if fh.Flags.Has(http2FlagDataPadded) {
		var err error
		payload, padSize, err = http2readByte(payload)
		if err != nil {
			countError("frame_data_pad_byte_short")
			return nil, err
		}
	}
	if int(padSize) > len(payload) {
		// 如果填充的长度大于
		// 帧有效载荷的长度，则接收方必须将此视为连接错误。
		// 文件：https:
		countError("frame_data_pad_too_big")
		return nil, http2connError{http2ErrCodeProtocol, "pad size larger than data payload"}
	}
	f.data = payload[:len(payload)-int(padSize)]
	return f, nil
}

var (
	http2errStreamID    = errors.New("invalid stream ID")
	http2errDepStreamID = errors.New("invalid dependent stream ID")
	http2errPadLength   = errors.New("pad length too large")
	http2errPadBytes    = errors.New("padding bytes must all be zeros unless AllowIllegalWrites is enabled")
)

func http2validStreamIDOrZero(streamID uint32) bool {
	return streamID&(1<<31) == 0
}

func http2validStreamID(streamID uint32) bool {
	return streamID != 0 && streamID&(1<<31) == 0
}

// WriteData写入数据帧。
// 
// 它将只对底层写入程序执行一次写入操作。
// 调用方有责任不违反最大帧大小
// 并且不同时调用其他写入方法。
func (f *http2Framer) WriteData(streamID uint32, endStream bool, data []byte) error {
	return f.WriteDataPadded(streamID, endStream, data, nil)
}

// WriteDapAdded写入带有可选填充的数据帧。
// 
// 如果pad为nil，则不发送填充位。
// 焊盘长度不得超过255字节。
// 除非设置了f.AllowIllegalWrites，否则pad的字节必须全部为零。
// 
// 它将只对底层编写器执行一次写入操作。
// 调用方有责任不违反最大帧大小
// 并且不同时调用其他写入方法。
func (f *http2Framer) WriteDataPadded(streamID uint32, endStream bool, data, pad []byte) error {
	if !http2validStreamID(streamID) && !f.AllowIllegalWrites {
		return http2errStreamID
	}
	if len(pad) > 0 {
		if len(pad) > 255 {
			return http2errPadLength
		}
		if !f.AllowIllegalWrites {
			for _, b := range pad {
				if b != 0 {
					// /“发送时必须将填充八位字节设置为零。”
					return http2errPadBytes
				}
			}
		}
	}
	var flags http2Flags
	if endStream {
		flags |= http2FlagDataEndStream
	}
	if pad != nil {
		flags |= http2FlagDataPadded
	}
	f.startWrite(http2FrameData, flags, streamID)
	if pad != nil {
		f.wbuf = append(f.wbuf, byte(len(pad)))
	}
	f.wbuf = append(f.wbuf, data...)
	f.wbuf = append(f.wbuf, pad...)
	return f.endWrite()
}

// 设置框架传递影响
// 端点通信方式的配置参数，例如对等
// 行为的首选项和约束。
// 参见http:
type http2SettingsFrame struct {
	http2FrameHeader
	p []byte
}

func http2parseSettingsFrame(_ *http2frameCache, fh http2FrameHeader, countError func(string), p []byte) (http2Frame, error) {
	if fh.Flags.Has(http2FlagSettingsAck) && fh.Length > 0 {
		// 设置此（ACK 0x1）位时，
		// 设置帧的有效负载必须为空。接收到设置了ACK标志和长度的
		// 设置帧时，必须将非0的字段值视为
		// 连接错误（第5.4.1节），类型为
		// frame\u SIZE\u error。
		countError("frame_settings_ack_with_length")
		return nil, http2ConnectionError(http2ErrCodeFrameSize)
	}
	if fh.StreamID != 0 {
		// 设置帧始终应用于连接，
		// 从不应用于单个流。
		// 设置帧的流标识符必须为零（0x0）。如果端点
		// 接收到一个设置帧，其流标识符
		// 字段不是0x0，则该端点必须
		// 以
		// 的连接错误（第5.4.1节）响应，并键入协议_错误。
		countError("frame_settings_has_stream")
		return nil, http2ConnectionError(http2ErrCodeProtocol)
	}
	if len(p)%6 != 0 {
		countError("frame_settings_mod_6")
		// 应为偶数的6字节设置。
		return nil, http2ConnectionError(http2ErrCodeFrameSize)
	}
	f := &http2SettingsFrame{http2FrameHeader: fh, p: p}
	if v, ok := f.Value(http2SettingInitialWindowSize); ok && v > (1<<31)-1 {
		countError("frame_settings_window_size_too_big")
		// 超过最大流量控制窗口大小2^31-1的值必须视为
		// 类型的连接错误（第5.4.1节）
		return nil, http2ConnectionError(http2ErrCodeFlowControl)
	}
	return f, nil
}

func (f *http2SettingsFrame) IsAck() bool {
	return f.http2FrameHeader.Flags.Has(http2FlagSettingsAck)
}

func (f *http2SettingsFrame) Value(id http2SettingID) (v uint32, ok bool) {
	f.checkValid()
	for i := 0; i < f.NumSettings(); i++ {
		if s := f.Setting(i); s.ID == id {
			return s.Val, true
		}
	}
	return 0, false
}

// Setting返回给定0索引处帧的设置。
// 索引必须大于等于0且小于f.NumSettings（）。
func (f *http2SettingsFrame) Setting(i int) http2Setting {
	buf := f.p
	return http2Setting{
		ID:  http2SettingID(binary.BigEndian.Uint16(buf[i*6 : i*6+2])),
		Val: binary.BigEndian.Uint32(buf[i*6+2 : i*6+6]),
	}
}

func (f *http2SettingsFrame) NumSettings() int { return len(f.p) / 6 }

// HasDuplicates报告f是否包含任何重复的设置ID。
func (f *http2SettingsFrame) HasDuplicates() bool {
	num := f.NumSettings()
	if num == 0 {
		return false
	}
	// 如果它足够小（通常情况下），只需执行n^2 
	// 操作，并避免地图分配。
	if num < 10 {
		for i := 0; i < num; i++ {
			idi := f.Setting(i).ID
			for j := i + 1; j < num; j++ {
				idj := f.Setting(j).ID
				if idi == idj {
					return true
				}
			}
		}
		return false
	}
	seen := map[http2SettingID]bool{}
	for i := 0; i < num; i++ {
		id := f.Setting(i).ID
		if seen[id] {
			return true
		}
		seen[id] = true
	}
	return false
}

// ForeachSetting为每个设置运行fn。
// 它停止并返回第一个错误。
func (f *http2SettingsFrame) ForeachSetting(fn func(http2Setting) error) error {
	f.checkValid()
	for i := 0; i < f.NumSettings(); i++ {
		if err := fn(f.Setting(i)); err != nil {
			return err
		}
	}
	return nil
}

// WriteSettings写入一个设置帧，其中指定了零个或多个设置
// 且未设置ACK位。
// 
// 它将只对底层写入程序执行一次写入操作。
// 调用方有责任不同时调用其他Write方法。
func (f *http2Framer) WriteSettings(settings ...http2Setting) error {
	f.startWrite(http2FrameSettings, 0, 0)
	for _, s := range settings {
		f.writeUint16(uint16(s.ID))
		f.writeUint32(s.Val)
	}
	return f.endWrite()
}

// WriteSettingsAck在设置ACK位的情况下写入一个空的设置帧。
// 
// 它将只对底层写入程序执行一次写入操作。
// 调用方有责任不同时调用其他Write方法。
func (f *http2Framer) WriteSettingsAck() error {
	f.startWrite(http2FrameSettings, http2FlagSettingsAck, 0)
	return f.endWrite()
}

// PingFrame是一种机制，用于测量来自发送方的最小往返时间
// 以及确定空闲连接
// 是否仍能正常工作。
// 参见http:
type http2PingFrame struct {
	http2FrameHeader
	Data [8]byte
}

func (f *http2PingFrame) IsAck() bool { return f.Flags.Has(http2FlagPingAck) }

func http2parsePingFrame(_ *http2frameCache, fh http2FrameHeader, countError func(string), payload []byte) (http2Frame, error) {
	if len(payload) != 8 {
		countError("frame_ping_length")
		return nil, http2ConnectionError(http2ErrCodeFrameSize)
	}
	if fh.StreamID != 0 {
		countError("frame_ping_has_stream")
		return nil, http2ConnectionError(http2ErrCodeProtocol)
	}
	f := &http2PingFrame{http2FrameHeader: fh}
	copy(f.Data[:], payload)
	return f, nil
}

func (f *http2Framer) WritePing(ack bool, data [8]byte) error {
	var flags http2Flags
	if ack {
		flags = http2FlagPingAck
	}
	f.startWrite(http2FramePing, flags, 0)
	f.writeBytes(data[:])
	return f.endWrite()
}

// 一个GoAwayFrame通知远程对等方停止在此连接上创建流。
// 见http:
type http2GoAwayFrame struct {
	http2FrameHeader
	LastStreamID uint32
	ErrCode      http2ErrCode
	debugData    []byte
}

// DebugData返回GOAWAY框架中的所有调试数据。其内容
// 未定义。
// 调用方不能在下一次
// 调用ReadFrame后保留返回的内存。
func (f *http2GoAwayFrame) DebugData() []byte {
	f.checkValid()
	return f.debugData
}

func http2parseGoAwayFrame(_ *http2frameCache, fh http2FrameHeader, countError func(string), p []byte) (http2Frame, error) {
	if fh.StreamID != 0 {
		countError("frame_goaway_has_stream")
		return nil, http2ConnectionError(http2ErrCodeProtocol)
	}
	if len(p) < 8 {
		countError("frame_goaway_short")
		return nil, http2ConnectionError(http2ErrCodeFrameSize)
	}
	return &http2GoAwayFrame{
		http2FrameHeader: fh,
		LastStreamID:     binary.BigEndian.Uint32(p[:4]) & (1<<31 - 1),
		ErrCode:          http2ErrCode(binary.BigEndian.Uint32(p[4:8])),
		debugData:        p[8:],
	}, nil
}

func (f *http2Framer) WriteGoAway(maxStreamID uint32, code http2ErrCode, debugData []byte) error {
	f.startWrite(http2FrameGoAway, 0, 0)
	f.writeUint32(maxStreamID & (1<<31 - 1))
	f.writeUint32(uint32(code))
	f.writeBytes(debugData)
	return f.endWrite()
}

// 未知帧是当帧类型未知或不存在特定的帧类型分析器时返回的帧类型。
type http2UnknownFrame struct {
	http2FrameHeader
	p []byte
}

// 有效载荷返回帧的有效载荷（在报头之后）。
// 在后续调用
// Framer之后调用此方法无效。ReadFrame，保留返回的切片也无效。
// 内存归编帧程序所有，在读取下一个
// 帧时无效。
func (f *http2UnknownFrame) Payload() []byte {
	f.checkValid()
	return f.p
}

func http2parseUnknownFrame(_ *http2frameCache, fh http2FrameHeader, countError func(string), p []byte) (http2Frame, error) {
	return &http2UnknownFrame{fh, p}, nil
}

// WindowUpdateName用于实现流控制。
// 参见http:
type http2WindowUpdateFrame struct {
	http2FrameHeader
	Increment uint32 // 从不使用高位设置进行读取
}

func http2parseWindowUpdateFrame(_ *http2frameCache, fh http2FrameHeader, countError func(string), p []byte) (http2Frame, error) {
	if len(p) != 4 {
		countError("frame_windowupdate_bad_len")
		return nil, http2ConnectionError(http2ErrCodeFrameSize)
	}
	inc := binary.BigEndian.Uint32(p[:4]) & 0x7fffffff // 屏蔽高保留位
	if inc == 0 {
		// 接收器必须将接收到的
		// 带有流控制窗口的窗口更新帧
		// 增量0视为
		// 类型协议错误的流错误（第5.4.2节）；连接流
		// 控制窗口上的错误必须视为连接
		// 错误（第5.4.1节）。
		if fh.StreamID == 0 {
			countError("frame_windowupdate_zero_inc_conn")
			return nil, http2ConnectionError(http2ErrCodeProtocol)
		}
		countError("frame_windowupdate_zero_inc_stream")
		return nil, http2streamError(fh.StreamID, http2ErrCodeProtocol)
	}
	return &http2WindowUpdateFrame{
		http2FrameHeader: fh,
		Increment:        inc,
	}, nil
}

// WriteWindowUpdate写入窗口更新框架。
// 增量值必须介于1和2147483647之间（含1和2147483647）。
// 如果流ID为零，则窗口更新将应用于整个
// 连接。
func (f *http2Framer) WriteWindowUpdate(streamID, incr uint32) error {
	// /“流量控制窗口增量的法定范围为1到2^31-1（2147483647）个八位字节。”
	if (incr < 1 || incr > 2147483647) && !f.AllowIllegalWrites {
		return errors.New("illegal window increment value")
	}
	f.startWrite(http2FrameWindowUpdate, 0, streamID)
	f.writeUint32(incr)
	return f.endWrite()
}

// headerFrame用于打开流，另外还携带一个
// 头块片段。
type http2HeadersFrame struct {
	http2FrameHeader

	// 如果在FrameHeader中设置了FlagHeaderPriority，则会设置优先级。
	Priority http2PriorityParam

	headerFragBuf []byte // 未拥有
}

func (f *http2HeadersFrame) HeaderBlockFragment() []byte {
	f.checkValid()
	return f.headerFragBuf
}

func (f *http2HeadersFrame) HeadersEnded() bool {
	return f.http2FrameHeader.Flags.Has(http2FlagHeadersEndHeaders)
}

func (f *http2HeadersFrame) StreamEnded() bool {
	return f.http2FrameHeader.Flags.Has(http2FlagHeadersEndStream)
}

func (f *http2HeadersFrame) HasPriority() bool {
	return f.http2FrameHeader.Flags.Has(http2FlagHeadersPriority)
}

func http2parseHeadersFrame(_ *http2frameCache, fh http2FrameHeader, countError func(string), p []byte) (_ http2Frame, err error) {
	hf := &http2HeadersFrame{
		http2FrameHeader: fh,
	}
	if fh.StreamID == 0 {
		// 头帧必须与流相关联。如果接收到流标识符字段为0x0的头帧
		// ，则接收方必须
		// 响应
		// 协议错误类型的连接错误（第5.4.1节）。
		countError("frame_headers_zero_stream")
		return nil, http2connError{http2ErrCodeProtocol, "HEADERS frame with stream ID 0"}
	}
	var padLength uint8
	if fh.Flags.Has(http2FlagHeadersPadded) {
		if p, padLength, err = http2readByte(p); err != nil {
			countError("frame_headers_pad_short")
			return
		}
	}
	if fh.Flags.Has(http2FlagHeadersPriority) {
		var v uint32
		p, v, err = http2readUint32(p)
		if err != nil {
			countError("frame_headers_prio_short")
			return nil, err
		}
		hf.Priority.StreamDep = v & 0x7fffffff
		hf.Priority.Exclusive = (v != hf.Priority.StreamDep) // 设置了高位
		p, hf.Priority.Weight, err = http2readByte(p)
		if err != nil {
			countError("frame_headers_prio_weight_short")
			return nil, err
		}
	}
	if len(p)-int(padLength) < 0 {
		countError("frame_headers_pad_too_big")
		return nil, http2streamError(fh.StreamID, http2ErrCodeProtocol)
	}
	hf.headerFragBuf = p[:len(p)-int(padLength)]
	return hf, nil
}

// HeadersFrameParam是用于写入HEADERS帧的参数。
type http2HeadersFrameParam struct {
	// StreamID是启动所需的流ID。
	StreamID uint32
	// BlockFragment是头块的一部分（或全部）。
	BlockFragment []byte

	// EndStream表示头块是端点为识别的流发送的最后一个头块。设置
	// 此标志会导致流进入“半关闭”
	// 状态之一。
	EndStream bool

	// EndHeaders表示此帧包含整个
	// 头块，后面没有任何
	// 继续帧。
	EndHeaders bool

	// PadLength是将
	// 添加到此帧的可选零字节数。
	PadLength uint8

	// 优先级，如果非零，则在头帧中包含流优先级信息
	// 。
	Priority http2PriorityParam
}

// WriteHeaders写入一个标题帧。
// 
// 这是一种低级头写入方法。对头文件和
// 进行编码，将其拆分为任何必要的连续帧在其他地方处理。
// 
// 它将只对底层写入程序执行一次写入操作。
// 调用方有责任不同时调用其他写入方法。
func (f *http2Framer) WriteHeaders(p http2HeadersFrameParam) error {
	if !http2validStreamID(p.StreamID) && !f.AllowIllegalWrites {
		return http2errStreamID
	}
	var flags http2Flags
	if p.PadLength != 0 {
		flags |= http2FlagHeadersPadded
	}
	if p.EndStream {
		flags |= http2FlagHeadersEndStream
	}
	if p.EndHeaders {
		flags |= http2FlagHeadersEndHeaders
	}
	if !p.Priority.IsZero() {
		flags |= http2FlagHeadersPriority
	}
	f.startWrite(http2FrameHeaders, flags, p.StreamID)
	if p.PadLength != 0 {
		f.writeByte(p.PadLength)
	}
	if !p.Priority.IsZero() {
		v := p.Priority.StreamDep
		if !http2validStreamIDOrZero(v) && !f.AllowIllegalWrites {
			return http2errDepStreamID
		}
		if p.Priority.Exclusive {
			v |= 1 << 31
		}
		f.writeUint32(v)
		f.writeByte(p.Priority.Weight)
	}
	f.wbuf = append(f.wbuf, p.BlockFragment...)
	f.wbuf = append(f.wbuf, http2padZeros[:p.PadLength]...)
	return f.endWrite()
}

// PriorityFrame指定流的发送方建议的优先级。
// 参见http:
type http2PriorityFrame struct {
	http2FrameHeader
	http2PriorityParam
}

// PriorityParam是流优先级参数。
type http2PriorityParam struct {
	// StreamDep是此流所依赖的
	// 流的31位流标识符。零表示没有
	// 依赖关系。
	StreamDep uint32

	// 独占性是指依赖项是否为独占性。
	Exclusive bool

	// 权重是流的零索引权重。它应该是
	// 与StreamDep一起设置，或者两者都不设置。根据
	// 规范，“向值中添加一个，以获得介于
	// 1和256之间的权重。”
	Weight uint8
}

func (p http2PriorityParam) IsZero() bool {
	return p == http2PriorityParam{}
}

func http2parsePriorityFrame(_ *http2frameCache, fh http2FrameHeader, countError func(string), payload []byte) (http2Frame, error) {
	if fh.StreamID == 0 {
		countError("frame_priority_zero_stream")
		return nil, http2connError{http2ErrCodeProtocol, "PRIORITY frame with stream ID 0"}
	}
	if len(payload) != 5 {
		countError("frame_priority_bad_length")
		return nil, http2connError{http2ErrCodeFrameSize, fmt.Sprintf("PRIORITY frame payload size was %d; want 5", len(payload))}
	}
	v := binary.BigEndian.Uint32(payload[:4])
	streamID := v & 0x7fffffff // 屏蔽高位
	return &http2PriorityFrame{
		http2FrameHeader: fh,
		http2PriorityParam: http2PriorityParam{
			Weight:    payload[4],
			StreamDep: streamID,
			Exclusive: streamID != v, // 高位设置了吗？
		},
	}, nil
}

// 写优先级写入优先级帧。
// 
// 它将只对底层写入程序执行一次写入操作。
// 调用方有责任不同时调用其他Write方法。
func (f *http2Framer) WritePriority(streamID uint32, p http2PriorityParam) error {
	if !http2validStreamID(streamID) && !f.AllowIllegalWrites {
		return http2errStreamID
	}
	if !http2validStreamIDOrZero(p.StreamDep) {
		return http2errDepStreamID
	}
	f.startWrite(http2FramePriority, 0, streamID)
	v := p.StreamDep
	if p.Exclusive {
		v |= 1 << 31
	}
	f.writeUint32(v)
	f.writeByte(p.Weight)
	return f.endWrite()
}

// RSTStreamFrame允许流的异常终止。
// 参见http:
type http2RSTStreamFrame struct {
	http2FrameHeader
	ErrCode http2ErrCode
}

func http2parseRSTStreamFrame(_ *http2frameCache, fh http2FrameHeader, countError func(string), p []byte) (http2Frame, error) {
	if len(p) != 4 {
		countError("frame_rststream_bad_len")
		return nil, http2ConnectionError(http2ErrCodeFrameSize)
	}
	if fh.StreamID == 0 {
		countError("frame_rststream_zero_stream")
		return nil, http2ConnectionError(http2ErrCodeProtocol)
	}
	return &http2RSTStreamFrame{fh, http2ErrCode(binary.BigEndian.Uint32(p[:4]))}, nil
}

// WriteRSTStream写入RST_流帧。
// 
// 它将只对基础写入程序执行一次写入操作。
// 调用方有责任不同时调用其他Write方法。
func (f *http2Framer) WriteRSTStream(streamID uint32, code http2ErrCode) error {
	if !http2validStreamID(streamID) && !f.AllowIllegalWrites {
		return http2errStreamID
	}
	f.startWrite(http2FrameRSTStream, 0, streamID)
	f.writeUint32(uint32(code))
	return f.endWrite()
}

// ContinuationFrame用于继续一系列头块片段。
// 参见http:
type http2ContinuationFrame struct {
	http2FrameHeader
	headerFragBuf []byte
}

func http2parseContinuationFrame(_ *http2frameCache, fh http2FrameHeader, countError func(string), p []byte) (http2Frame, error) {
	if fh.StreamID == 0 {
		countError("frame_continuation_zero_stream")
		return nil, http2connError{http2ErrCodeProtocol, "CONTINUATION frame with stream ID 0"}
	}
	return &http2ContinuationFrame{fh, p}, nil
}

func (f *http2ContinuationFrame) HeaderBlockFragment() []byte {
	f.checkValid()
	return f.headerFragBuf
}

func (f *http2ContinuationFrame) HeadersEnded() bool {
	return f.http2FrameHeader.Flags.Has(http2FlagContinuationEndHeaders)
}

// WriteContinuation写入一个延续帧。
// 
// 它将只对底层写入程序执行一次写入操作。
// 调用方有责任不同时调用其他Write方法。
func (f *http2Framer) WriteContinuation(streamID uint32, endHeaders bool, headerBlockFragment []byte) error {
	if !http2validStreamID(streamID) && !f.AllowIllegalWrites {
		return http2errStreamID
	}
	var flags http2Flags
	if endHeaders {
		flags |= http2FlagContinuationEndHeaders
	}
	f.startWrite(http2FrameContinuation, flags, streamID)
	f.wbuf = append(f.wbuf, headerBlockFragment...)
	return f.endWrite()
}

// PushPromiseFrame用于启动服务器流。
// 参见http:
type http2PushPromiseFrame struct {
	http2FrameHeader
	PromiseID     uint32
	headerFragBuf []byte // 未拥有
}

func (f *http2PushPromiseFrame) HeaderBlockFragment() []byte {
	f.checkValid()
	return f.headerFragBuf
}

func (f *http2PushPromiseFrame) HeadersEnded() bool {
	return f.http2FrameHeader.Flags.Has(http2FlagPushPromiseEndHeaders)
}

func http2parsePushPromise(_ *http2frameCache, fh http2FrameHeader, countError func(string), p []byte) (_ http2Frame, err error) {
	pp := &http2PushPromiseFrame{
		http2FrameHeader: fh,
	}
	if pp.StreamID == 0 {
		// 推送承诺帧必须与现有的
		// 对等启动流相关联。
		// 推送承诺帧的流标识符表示它与
		// 关联的流。如果流标识符字段指定值
		// 0x0，则接收方必须以协议错误类型的连接错误
		// （第5.4.1节）进行响应。
		countError("frame_pushpromise_zero_stream")
		return nil, http2ConnectionError(http2ErrCodeProtocol)
	}
	// PUSH_PROMISE框架包含可选填充。
	// 填充字段和标志与为数据帧定义的字段和标志相同
	var padLength uint8
	if fh.Flags.Has(http2FlagPushPromisePadded) {
		if p, padLength, err = http2readByte(p); err != nil {
			countError("frame_pushpromise_pad_short")
			return
		}
	}

	p, pp.PromiseID, err = http2readUint32(p)
	if err != nil {
		countError("frame_pushpromise_promiseid_short")
		return
	}
	pp.PromiseID = pp.PromiseID & (1<<31 - 1)

	if int(padLength) > len(p) {
		// 与数据帧类似，如果填充长度超过正文，则会出错。
		countError("frame_pushpromise_pad_too_big")
		return nil, http2ConnectionError(http2ErrCodeProtocol)
	}
	pp.headerFragBuf = p[:len(p)-int(padLength)]
	return pp, nil
}

// PushPromiseParam是用于编写PUSH_承诺框架的参数。
type http2PushPromiseParam struct {
	// StreamID是启动所需的流ID。
	StreamID uint32

	// PromiseID是所需的流ID，此
	// 推送承诺
	PromiseID uint32

	// BlockFragment是头块的一部分（或全部）。
	BlockFragment []byte

	// EndHeaders表示此帧包含整个
	// 头块，后面没有任何
	// 继续帧。
	EndHeaders bool

	// PadLength是将
	// 添加到此帧的可选字节数。
	PadLength uint8
}

// WritePushPromise编写一个PushPromise框架。
// 
// 与头帧一样，这是编写单个帧的低级调用。继续帧在其他地方处理。
// 
// 它将只对底层写入程序执行一次写入操作。
// 调用方有责任不同时调用其他Write方法。
func (f *http2Framer) WritePushPromise(p http2PushPromiseParam) error {
	if !http2validStreamID(p.StreamID) && !f.AllowIllegalWrites {
		return http2errStreamID
	}
	var flags http2Flags
	if p.PadLength != 0 {
		flags |= http2FlagPushPromisePadded
	}
	if p.EndHeaders {
		flags |= http2FlagPushPromiseEndHeaders
	}
	f.startWrite(http2FramePushPromise, flags, p.StreamID)
	if p.PadLength != 0 {
		f.writeByte(p.PadLength)
	}
	if !http2validStreamID(p.PromiseID) && !f.AllowIllegalWrites {
		return http2errStreamID
	}
	f.writeUint32(p.PromiseID)
	f.wbuf = append(f.wbuf, p.BlockFragment...)
	f.wbuf = append(f.wbuf, http2padZeros[:p.PadLength]...)
	return f.endWrite()
}

// WriteRawFrame写入原始帧。这可用于写入
// 此包未知的扩展帧。
func (f *http2Framer) WriteRawFrame(t http2FrameType, flags http2Flags, streamID uint32, payload []byte) error {
	f.startWrite(t, flags, streamID)
	f.writeBytes(payload)
	return f.endWrite()
}

func http2readByte(p []byte) (remain []byte, b byte, err error) {
	if len(p) == 0 {
		return nil, 0, io.ErrUnexpectedEOF
	}
	return p[1:], p[0], nil
}

func http2readUint32(p []byte) (remain []byte, v uint32, err error) {
	if len(p) < 4 {
		return nil, 0, io.ErrUnexpectedEOF
	}
	return p[4:], binary.BigEndian.Uint32(p[:4]), nil
}

type http2streamEnder interface {
	StreamEnded() bool
}

type http2headersEnder interface {
	HeadersEnded() bool
}

type http2headersOrContinuation interface {
	http2headersEnder
	HeaderBlockFragment() []byte
}

// 元头帧是一个头帧和
// 零个或多个连续帧的表示，以及对
// 其HPACK编码内容的解码。
// 
// 这种类型的帧不会出现在导线上，只有在编帧时，编帧者才会返回
// 帧。ReadMetaHeaders已设置。
type http2MetaHeadersFrame struct {
	*http2HeadersFrame

	// 字段是包含在标题和
	// 继续帧中的字段。底层切片归
	// 编帧程序所有，在下次调用
	// ReadFrame后不能保留。
	// 
	// 保证字段的http2顺序正确，并且
	// 没有未知的伪头字段或无效的头
	// 字段名称或值。但是，所需的伪头字段可能是
	// 缺失。使用MetaHeadersFrame。伪访问器
	// 方法访问伪头。
	Fields []hpack.HeaderField

	// 截断是指是否达到了最大标题列表大小限制
	// 并且字段不完整。然而，hpack解码器状态仍然是
	// 有效。
	Truncated bool
}

// PseudoValue返回给定的伪头字段的值。
// 提供的伪字段不应包含前导冒号。
func (mh *http2MetaHeadersFrame) PseudoValue(pseudo string) string {
	for _, hf := range mh.Fields {
		if !hf.IsPseudo() {
			return ""
		}
		if hf.Name[1:] == pseudo {
			return hf.Value
		}
	}
	return ""
}

// RegularFields返回mh的常规（非伪）头字段。
// 调用方不拥有返回的切片。
func (mh *http2MetaHeadersFrame) RegularFields() []hpack.HeaderField {
	for i, hf := range mh.Fields {
		if !hf.IsPseudo() {
			return mh.Fields[i:]
		}
	}
	return nil
}

// PseudoFields返回mh的伪头字段。
// 调用方不拥有返回的切片。
func (mh *http2MetaHeadersFrame) PseudoFields() []hpack.HeaderField {
	for i, hf := range mh.Fields {
		if !hf.IsPseudo() {
			return mh.Fields[:i]
		}
	}
	return mh.Fields
}

func (mh *http2MetaHeadersFrame) checkPseudos() error {
	var isRequest, isResponse bool
	pf := mh.PseudoFields()
	for i, hf := range pf {
		switch hf.Name {
		case ":method", ":path", ":scheme", ":authority":
			isRequest = true
		case ":status":
			isResponse = true
		default:
			return http2pseudoHeaderError(hf.Name)
		}
		// 检查是否有重复项。
		// 这将是一个糟糕的算法，但N是4。
		// 这不分配。
		for _, hf2 := range pf[:i] {
			if hf.Name == hf2.Name {
				return http2duplicatePseudoHeaderError(hf.Name)
			}
		}
	}
	if isRequest && isResponse {
		return http2errMixPseudoHeaderTypes
	}
	return nil
}

func (fr *http2Framer) maxHeaderStringLen() int {
	v := fr.maxHeaderListSize()
	if uint32(int(v)) == v {
		return int(v)
	}
	// 反正他们的MaxHeaderBytes有一个疯狂的大数字，
	// 所以给他们无限的头长度：
	return 0
}

// readMetaFrame从fr和
// 返回0个或多个连续帧，将它们合并到提供的hf中，并返回MetaHeaderFrame 
// 和解码的hpack值。
func (fr *http2Framer) readMetaFrame(hf *http2HeadersFrame) (*http2MetaHeadersFrame, error) {
	if fr.AllowIllegalReads {
		return nil, errors.New("illegal use of AllowIllegalReads with ReadMetaHeaders")
	}
	mh := &http2MetaHeadersFrame{
		http2HeadersFrame: hf,
	}
	var remainSize = fr.maxHeaderListSize()
	var sawRegular bool

	var invalid error // 伪头字段错误
	hdec := fr.ReadMetaHeaders
	hdec.SetEmitEnabled(true)
	hdec.SetMaxStringLength(fr.maxHeaderStringLen())
	hdec.SetEmitFunc(func(hf hpack.HeaderField) {
		if http2VerboseLogs && fr.logReads {
			fr.debugReadLoggerf("http2: decoded hpack field %+v", hf)
		}
		if !httpguts.ValidHeaderFieldValue(hf.Value) {
			invalid = http2headerFieldValueError(hf.Value)
		}
		isPseudo := strings.HasPrefix(hf.Name, ":")
		if isPseudo {
			if sawRegular {
				invalid = http2errPseudoAfterRegular
			}
		} else {
			sawRegular = true
			if !http2validWireHeaderFieldName(hf.Name) {
				invalid = http2headerFieldNameError(hf.Name)
			}
		}

		if invalid != nil {
			hdec.SetEmitEnabled(false)
			return
		}

		size := hf.Size()
		if size > remainSize {
			hdec.SetEmitEnabled(false)
			mh.Truncated = true
			return
		}
		remainSize -= size

		mh.Fields = append(mh.Fields, hf)
	})
	// 丢失对MetaHeaderFrame的引用：
	defer hdec.SetEmitFunc(func(hf hpack.HeaderField) {})

	var hc http2headersOrContinuation = hf
	for {
		frag := hc.HeaderBlockFragment()
		if _, err := hdec.Write(frag); err != nil {
			return nil, http2ConnectionError(http2ErrCodeCompression)
		}

		if hc.HeadersEnded() {
			break
		}
		if f, err := fr.ReadFrame(); err != nil {
			return nil, err
		} else {
			hc = f.(*http2ContinuationFrame) // 由checkFrameOrder保证
		}
	}

	mh.http2HeadersFrame.headerFragBuf = nil
	mh.http2HeadersFrame.invalidate()

	if err := hdec.Close(); err != nil {
		return nil, http2ConnectionError(http2ErrCodeCompression)
	}
	if invalid != nil {
		fr.errDetail = invalid
		if http2VerboseLogs {
			log.Printf("http2: invalid header: %v", invalid)
		}
		return nil, http2StreamError{mh.StreamID, http2ErrCodeProtocol, invalid}
	}
	if err := mh.checkPseudos(); err != nil {
		fr.errDetail = err
		if http2VerboseLogs {
			log.Printf("http2: invalid pseudo headers: %v", err)
		}
		return nil, http2StreamError{mh.StreamID, http2ErrCodeProtocol, err}
	}
	return mh, nil
}

func http2summarizeFrame(f http2Frame) string {
	var buf bytes.Buffer
	f.Header().writeDebug(&buf)
	switch f := f.(type) {
	case *http2SettingsFrame:
		n := 0
		f.ForeachSetting(func(s http2Setting) error {
			n++
			if n == 1 {
				buf.WriteString(", settings:")
			}
			fmt.Fprintf(&buf, " %v=%v,", s.ID, s.Val)
			return nil
		})
		if n > 0 {
			buf.Truncate(buf.Len() - 1) // 删除尾随逗号
		}
	case *http2DataFrame:
		data := f.Data()
		const max = 256
		if len(data) > max {
			data = data[:max]
		}
		fmt.Fprintf(&buf, " data=%q", data)
		if len(f.Data()) > max {
			fmt.Fprintf(&buf, " (%d bytes omitted)", len(f.Data())-max)
		}
	case *http2WindowUpdateFrame:
		if f.StreamID == 0 {
			buf.WriteString(" (conn)")
		}
		fmt.Fprintf(&buf, " incr=%v", f.Increment)
	case *http2PingFrame:
		fmt.Fprintf(&buf, " ping=%q", f.Data[:])
	case *http2GoAwayFrame:
		fmt.Fprintf(&buf, " LastStreamID=%v ErrCode=%v Debug=%q",
			f.LastStreamID, f.ErrCode, f.debugData)
	case *http2RSTStreamFrame:
		fmt.Fprintf(&buf, " ErrCode=%v", f.ErrCode)
	}
	return buf.String()
}

func http2traceHasWroteHeaderField(trace *httptrace.ClientTrace) bool {
	return trace != nil && trace.WroteHeaderField != nil
}

func http2traceWroteHeaderField(trace *httptrace.ClientTrace, k, v string) {
	if trace != nil && trace.WroteHeaderField != nil {
		trace.WroteHeaderField(k, []string{v})
	}
}

func http2traceGot1xxResponseFunc(trace *httptrace.ClientTrace) func(int, textproto.MIMEHeader) error {
	if trace != nil {
		return trace.Got1xxResponse
	}
	return nil
}

// DialtSwithContext使用tls。Go 1.15中添加的拨号器，用于打开TLS 
// 连接。
func (t *http2Transport) dialTLSWithContext(ctx context.Context, network, addr string, cfg *tls.Config) (*tls.Conn, error) {
	dialer := &tls.Dialer{
		Config: cfg,
	}
	cn, err := dialer.DialContext(ctx, network, addr)
	if err != nil {
		return nil, err
	}
	tlsCn := cn.(*tls.Conn) // DialContext comment承诺这将永远成功
	return tlsCn, nil
}

var http2DebugGoroutines = os.Getenv("DEBUG_HTTP2_GOROUTINES") == "1"

type http2goroutineLock uint64

func http2newGoroutineLock() http2goroutineLock {
	if !http2DebugGoroutines {
		return 0
	}
	return http2goroutineLock(http2curGoroutineID())
}

func (g http2goroutineLock) check() {
	if !http2DebugGoroutines {
		return
	}
	if http2curGoroutineID() != uint64(g) {
		panic("running on the wrong goroutine")
	}
}

func (g http2goroutineLock) checkNotOn() {
	if !http2DebugGoroutines {
		return
	}
	if http2curGoroutineID() == uint64(g) {
		panic("running on the wrong goroutine")
	}
}

var http2goroutineSpace = []byte("goroutine ")

func http2curGoroutineID() uint64 {
	bp := http2littleBuf.Get().(*[]byte)
	defer http2littleBuf.Put(bp)
	b := *bp
	b = b[:runtime.Stack(b, false)]
	// 解析“goroutine 4707[”中的4707
	b = bytes.TrimPrefix(b, http2goroutineSpace)
	i := bytes.IndexByte(b, ' ')
	if i < 0 {
		panic(fmt.Sprintf("No space found in %q", b))
	}
	b = b[:i]
	n, err := http2parseUintBytes(b, 10, 64)
	if err != nil {
		panic(fmt.Sprintf("Failed to parse goroutine ID out of %q: %v", b, err))
	}
	return n
}

var http2littleBuf = sync.Pool{
	New: func() interface{} {
		buf := make([]byte, 64)
		return &buf
	},
}

// parseUintBytes类似于strconv.ParseUint，但使用[]字节。
func http2parseUintBytes(s []byte, base int, bitSize int) (n uint64, err error) {
	var cutoff, maxVal uint64

	if bitSize == 0 {
		bitSize = int(strconv.IntSize)
	}

	s0 := s
	switch {
	case len(s) < 1:
		err = strconv.ErrSyntax
		goto Error

	case 2 <= base && base <= 36:
		// 有效基数；无需操作

	case base == 0:
		// 查找八进制、十六进制前缀。
		switch {
		case s[0] == '0' && len(s) > 1 && (s[1] == 'x' || s[1] == 'X'):
			base = 16
			s = s[2:]
			if len(s) < 1 {
				err = strconv.ErrSyntax
				goto Error
			}
		case s[0] == '0':
			base = 8
		default:
			base = 10
		}

	default:
		err = errors.New("invalid base " + strconv.Itoa(base))
		goto Error
	}

	n = 0
	cutoff = http2cutoff64(base)
	maxVal = 1<<uint(bitSize) - 1

	for i := 0; i < len(s); i++ {
		var v byte
		d := s[i]
		switch {
		case '0' <= d && d <= '9':
			v = d - '0'
		case 'a' <= d && d <= 'z':
			v = d - 'a' + 10
		case 'A' <= d && d <= 'Z':
			v = d - 'A' + 10
		default:
			n = 0
			err = strconv.ErrSyntax
			goto Error
		}
		if int(v) >= base {
			n = 0
			err = strconv.ErrSyntax
			goto Error
		}

		if n >= cutoff {
			// n*base溢出
			n = 1<<64 - 1
			err = strconv.ErrRange
			goto Error
		}
		n *= uint64(base)

		n1 := n + uint64(v)
		if n1 < n || n1 > maxVal {
			// n+v溢出
			n = 1<<64 - 1
			err = strconv.ErrRange
			goto Error
		}
		n = n1
	}

	return n, nil

Error:
	return n, &strconv.NumError{Func: "ParseUint", Num: string(s0), Err: err}
}

// 返回第一个数字n，使n*base>=1<<64。
func http2cutoff64(base int) uint64 {
	if base < 2 {
		return 0
	}
	return (1<<64-1)/uint64(base) + 1
}

var (
	http2commonBuildOnce   sync.Once
	http2commonLowerHeader map[string]string // Go Canonical Case->lower Case 
	http2commonCanonHeader map[string]string // lower Case->Go Canonical Case 
)

func http2buildCommonHeaderMapsOnce() {
	http2commonBuildOnce.Do(http2buildCommonHeaderMaps)
}

func http2buildCommonHeaderMaps() {
	common := []string{
		"accept",
		"accept-charset",
		"accept-encoding",
		"accept-language",
		"accept-ranges",
		"age",
		"access-control-allow-origin",
		"allow",
		"authorization",
		"cache-control",
		"content-disposition",
		"content-encoding",
		"content-language",
		"content-length",
		"content-location",
		"content-range",
		"content-type",
		"cookie",
		"date",
		"etag",
		"expect",
		"expires",
		"from",
		"host",
		"if-match",
		"if-modified-since",
		"if-none-match",
		"if-unmodified-since",
		"last-modified",
		"link",
		"location",
		"max-forwards",
		"proxy-authenticate",
		"proxy-authorization",
		"range",
		"referer",
		"refresh",
		"retry-after",
		"server",
		"set-cookie",
		"strict-transport-security",
		"trailer",
		"transfer-encoding",
		"user-agent",
		"vary",
		"via",
		"www-authenticate",
	}
	http2commonLowerHeader = make(map[string]string, len(common))
	http2commonCanonHeader = make(map[string]string, len(common))
	for _, v := range common {
		chk := CanonicalHeaderKey(v)
		http2commonLowerHeader[chk] = v
		http2commonCanonHeader[v] = chk
	}
}

func http2lowerHeader(v string) (lower string, ascii bool) {
	http2buildCommonHeaderMapsOnce()
	if s, ok := http2commonLowerHeader[v]; ok {
		return s, true
	}
	return http2asciiToLower(v)
}

var (
	http2VerboseLogs    bool
	http2logFrameWrites bool
	http2logFrameReads  bool
	http2inTests        bool
)

func init() {
	e := os.Getenv("GODEBUG")
	if strings.Contains(e, "http2debug=1") {
		http2VerboseLogs = true
	}
	if strings.Contains(e, "http2debug=2") {
		http2VerboseLogs = true
		http2logFrameWrites = true
		http2logFrameReads = true
	}
}

const (
	// ClientPreference是必须由新的
	// 连接从客户端发送的字符串。
	http2ClientPreface = "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"

	// SETTINGS_MAX_FRAME_SIZE default 
	// http:
	http2initialMaxFrameSize = 16384

	// NextProtoTLS是在
	// http/2的TLS设置期间协商的NPN/ALPN协议。
	http2NextProtoTLS = "h2"

	// http:
	http2initialHeaderTableSize = 4096

	http2initialWindowSize = 65535 // 6.9.2初始流控制窗口大小

	http2defaultMaxReadFrameSize = 1 << 20
)

var (
	http2clientPreface = []byte(http2ClientPreface)
)

type http2streamState int

// http/2流状态。
// 参见http:
// 
// 为了简单起见，服务器代码将“保留（本地）”合并到
// “半关闭（远程）”中。这是一个少了一个国家过渡到轨道。
// 唯一的缺点是我们发送的PUSH_承诺比允许的稍微少一些。更多讨论请点击这里：
// lists.w3.org/Archives/Public/ietf-http-wg/2016JulSep/0599.html
// 
// “保留（远程）”被省略，因为客户端代码不支持服务器推送。
const (
	http2stateIdle http2streamState = iota
	http2stateOpen
	http2stateHalfClosedLocal
	http2stateHalfClosedRemote
	http2stateClosed
)

var http2stateName = [...]string{
	http2stateIdle:             "Idle",
	http2stateOpen:             "Open",
	http2stateHalfClosedLocal:  "HalfClosedLocal",
	http2stateHalfClosedRemote: "HalfClosedRemote",
	http2stateClosed:           "Closed",
}

func (st http2streamState) String() string {
	return http2stateName[st]
}

// 设置是一个设置参数：它是哪个设置，以及它的值。
type http2Setting struct {
	// ID是正在设置的设置。
	// 请参见http:
	ID http2SettingID

	// 值为Val。
	Val uint32
}

func (s http2Setting) String() string {
	return fmt.Sprintf("[%v = %d]", s.ID, s.Val)
}

// Valid报告设置是否有效。
func (s http2Setting) Valid() error {
	// 6.5.2定义的设置参数中的限制和错误代码
	switch s.ID {
	case http2SettingEnablePush:
		if s.Val != 1 && s.Val != 0 {
			return http2ConnectionError(http2ErrCodeProtocol)
		}
	case http2SettingInitialWindowSize:
		if s.Val > 1<<31-1 {
			return http2ConnectionError(http2ErrCodeFlowControl)
		}
	case http2SettingMaxFrameSize:
		if s.Val < 16384 || s.Val > 1<<24-1 {
			return http2ConnectionError(http2ErrCodeProtocol)
		}
	}
	return nil
}

// 设置ID是
// http2.github.io/http2-spec/#iana-设置
type http2SettingID uint16

const (
	http2SettingHeaderTableSize      http2SettingID = 0x1
	http2SettingEnablePush           http2SettingID = 0x2
	http2SettingMaxConcurrentStreams http2SettingID = 0x3
	http2SettingInitialWindowSize    http2SettingID = 0x4
	http2SettingMaxFrameSize         http2SettingID = 0x5
	http2SettingMaxHeaderListSize    http2SettingID = 0x6
)

var http2settingName = map[http2SettingID]string{
	http2SettingHeaderTableSize:      "HEADER_TABLE_SIZE",
	http2SettingEnablePush:           "ENABLE_PUSH",
	http2SettingMaxConcurrentStreams: "MAX_CONCURRENT_STREAMS",
	http2SettingInitialWindowSize:    "INITIAL_WINDOW_SIZE",
	http2SettingMaxFrameSize:         "MAX_FRAME_SIZE",
	http2SettingMaxHeaderListSize:    "MAX_HEADER_LIST_SIZE",
}

func (s http2SettingID) String() string {
	if v, ok := http2settingName[s]; ok {
		return v
	}
	return fmt.Sprintf("UNKNOWN_SETTING_%d", uint16(s))
}

// validWireHeaderFieldName报告v是否为有效的头字段
// 名称（键）。参见httpguts。基本规则的有效头名。
// 
// 此外，http2说：
// “就像在HTTP/1.x中一样，头字段名是ASCII 
// 字符的字符串，以不区分大小写的
// 方式进行比较。但是，头字段名必须先转换为
// 小写，然后才能在HTTP/2中进行编码。”
func http2validWireHeaderFieldName(v string) bool {
	if len(v) == 0 {
		return false
	}
	for _, r := range v {
		if !httpguts.IsTokenRune(r) {
			return false
		}
		if 'A' <= r && r <= 'Z' {
			return false
		}
	}
	return true
}

func http2httpCodeString(code int) string {
	switch code {
	case 200:
		return "200"
	case 404:
		return "404"
	}
	return strconv.Itoa(code)
}

// 来自pkg io 
type http2stringWriter interface {
	WriteString(s string) (n int, err error)
}

// 一个门让两个Goroutine协调他们的活动。
type http2gate chan struct{}

func (g http2gate) Done() { g <- struct{}{} }

func (g http2gate) Wait() { <-g }

// 服务员就像同步器。WaitGroup，但只有1到0（打开到关闭）。
type http2closeWaiter chan struct{}

// Init使CloseWater可用。
// 之所以存在，是因为可以在更大的结构中放置closewater值，并将互斥和Cond的内存放在同一个
// 分配中。
func (cw *http2closeWaiter) Init() {
	*cw = make(chan struct{})
}

// Close将Closer服务员标记为closed，并取消阻止任何服务员。
func (cw http2closeWaiter) Close() {
	close(cw)
}

// 等待服务员关门。
func (cw http2closeWaiter) Wait() {
	<-cw
}

// bufferedWriter是一个缓冲写入程序，可以写入w。
// 它的缓冲写入程序根据需要进行延迟分配，以最大限度地减少
// 在多个连接中的空闲内存使用。
type http2bufferedWriter struct {
	_  http2incomparable
	w  io.Writer     // 不可变
	bw *bufio.Writer // 缓冲数据时非零
}

func http2newBufferedWriter(w io.Writer) *http2bufferedWriter {
	return &http2bufferedWriter{w: w}
}

// bufWriterPoolBufferSize是bufio的大小。作者的
// 使用bufWriterPool创建的缓冲区。
// 
// TODO:选择一个不太随意的值？这至少比
// /（3 x典型的1500字节MTU）低一点。除此之外，
// 没有太多考虑。
const http2bufWriterPoolBufferSize = 4 << 10

var http2bufWriterPool = sync.Pool{
	New: func() interface{} {
		return bufio.NewWriterSize(nil, http2bufWriterPoolBufferSize)
	},
}

func (w *http2bufferedWriter) Available() int {
	if w.bw == nil {
		return http2bufWriterPoolBufferSize
	}
	return w.bw.Available()
}

func (w *http2bufferedWriter) Write(p []byte) (n int, err error) {
	if w.bw == nil {
		bw := http2bufWriterPool.Get().(*bufio.Writer)
		bw.Reset(w.w)
		w.bw = bw
	}
	return w.bw.Write(p)
}

func (w *http2bufferedWriter) Flush() error {
	bw := w.bw
	if bw == nil {
		return nil
	}
	err := bw.Flush()
	bw.Reset(nil)
	http2bufWriterPool.Put(bw)
	w.bw = nil
	return err
}

func http2mustUint31(v int32) uint32 {
	if v < 0 || v > 2147483647 {
		panic("out of range")
	}
	return uint32(v)
}

// body AllowedForStatus报告给定的响应状态代码
// 是否允许正文。参见RFC 7230，第3.3节。
func http2bodyAllowedForStatus(status int) bool {
	switch {
	case status >= 100 && status <= 199:
		return false
	case status == 204:
		return false
	case status == 304:
		return false
	}
	return true
}

type http2httpError struct {
	_       http2incomparable
	msg     string
	timeout bool
}

func (e *http2httpError) Error() string { return e.msg }

func (e *http2httpError) Timeout() bool { return e.timeout }

func (e *http2httpError) Temporary() bool { return true }

var http2errTimeout error = &http2httpError{msg: "http2: timeout awaiting response headers", timeout: true}

type http2connectionStater interface {
	ConnectionState() tls.ConnectionState
}

var http2sorterPool = sync.Pool{New: func() interface{} { return new(http2sorter) }}

type http2sorter struct {
	v []string // 由分拣机
}

func (s *http2sorter) Len() int { return len(s.v) }

func (s *http2sorter) Swap(i, j int) { s.v[i], s.v[j] = s.v[j], s.v[i] }

func (s *http2sorter) Less(i, j int) bool { return s.v[i] < s.v[j] }

// Keys返回h的已排序密钥。
// 
// 返回的切片仅在s再次使用或返回到
// 其池之前有效。
func (s *http2sorter) Keys(h Header) []string {
	keys := s.v[:0]
	for k := range h {
		keys = append(keys, k)
	}
	s.v = keys
	sort.Sort(s)
	return keys
}

func (s *http2sorter) SortStrings(ss []string) {
	// 我们的分拣机在分拣机拥有的s.v上工作，所以
	// 在我们对用户的缓冲区进行排序时将其隐藏起来。
	save := s.v
	s.v = ss
	sort.Sort(s)
	s.v = save
}

// validPseudoPath报告v是否为有效的：路径伪头
// 值。对于选项请求，它必须是以“/”开头的非空字符串。
// 
// 目前，这只是一个快速检查，用于决定何时清除
// 在从传输发送请求之前清除不透明的URL。
// 见戈朗。org/issue/16847 
// 
// 我们曾经强制要求路径也不以“/”开头，但
// 谷歌的GFE接受这些路径并由Chrome发送，所以忽略
// 规范的这一部分。参见golang。org/issue/19103。
func http2validPseudoPath(v string) bool {
	return (len(v) > 0 && v[0] == '/') || v == "*"
}

// 不可比较是一种零宽度、不可比较的类型。将其添加到结构
// 也会使该结构不可比较，并且通常不会添加任何大小的
// 只要它是第一个。
type http2incomparable [0]func()

// 管道是一种goroutine安全io。读卡器/io。一对作家。就像
// io。除了没有PipeReader/PipeWriter的一半之外，还有一个接口
// 底层缓冲区。（io.Pipe始终未缓冲）
type http2pipe struct {
	mu       sync.Mutex
	c        sync.Cond       // c.L延迟初始化为&p.mu 
	b        http2pipeBuffer // nil当读取完
	unread   int             // 字节未读取完成
	err      error           // 读取错误一旦为空。非零表示关闭。
	breakErr error           // 立即读取错误（调用者看不到b的其余部分）
	donec    chan struct{}   // 错误时关闭
	readFn   func()          // 在错误
}

type http2pipeBuffer interface {
	Len() int
	io.Writer
	io.Reader
}

// setBuffer初始化管道缓冲区之前在读取中运行的可选代码。
// 如果管道已经关闭，则无效。
func (p *http2pipe) setBuffer(b http2pipeBuffer) {
	p.mu.Lock()
	defer p.mu.Unlock()
	if p.err != nil || p.breakErr != nil {
		return
	}
	p.b = b
}

func (p *http2pipe) Len() int {
	p.mu.Lock()
	defer p.mu.Unlock()
	if p.b == nil {
		return p.unread
	}
	return p.b.Len()
}

// 读取等待数据可用并将字节
// 从缓冲区复制到p。
func (p *http2pipe) Read(d []byte) (n int, err error) {
	p.mu.Lock()
	defer p.mu.Unlock()
	if p.c.L == nil {
		p.c.L = &p.mu
	}
	for {
		if p.breakErr != nil {
			return 0, p.breakErr
		}
		if p.b != nil && p.b.Len() > 0 {
			return p.b.Read(d)
		}
		if p.err != nil {
			if p.readFn != nil {
				p.readFn()     // 例如，复制拖车
				p.readFn = nil // 不像p那样粘性。err 
			}
			p.b = nil
			return 0, p.err
		}
		p.c.Wait()
	}
}

var http2errClosedPipeWrite = errors.New("write on closed buffer")

// 将字节从p复制到缓冲区并唤醒读卡器。
// 写入的数据超过缓冲区的容量是错误的。
func (p *http2pipe) Write(d []byte) (n int, err error) {
	p.mu.Lock()
	defer p.mu.Unlock()
	if p.c.L == nil {
		p.c.L = &p.mu
	}
	defer p.c.Signal()
	if p.err != nil {
		return 0, http2errClosedPipeWrite
	}
	if p.breakErr != nil {
		p.unread += len(d)
		return len(d), nil // 没有读卡器时放弃
	}
	return p.b.Write(d)
}

// CloseWithError导致下一次读取（唤醒当前被阻止的
// 读取，如果需要）在读取所有数据后返回提供的错误
// 读取。
// 
// 错误必须为非零。
func (p *http2pipe) CloseWithError(err error) { p.closeWithError(&p.err, err, nil) }

// 中断错误导致下一次读取（唤醒当前被阻止的
// 读取，如果需要）立即返回提供的错误，而不会导致
// 等待未读数据。
func (p *http2pipe) BreakWithError(err error) { p.closeWithError(&p.breakErr, err, nil) }

// closeWithErrorAndCode类似于CloseWithError，但也设置了一些代码，以便在返回错误之前在调用方的goroutine中运行
// 。
func (p *http2pipe) closeWithErrorAndCode(err error, fn func()) { p.closeWithError(&p.err, err, fn) }

func (p *http2pipe) closeWithError(dst *error, err error, fn func()) {
	if err == nil {
		panic("err must be non-nil")
	}
	p.mu.Lock()
	defer p.mu.Unlock()
	if p.c.L == nil {
		p.c.L = &p.mu
	}
	defer p.c.Signal()
	if *dst != nil {
		// 已经完成。
		return
	}
	p.readFn = fn
	if dst == &p.breakErr {
		if p.b != nil {
			p.unread += p.b.Len()
		}
		p.b = nil
	}
	*dst = err
	p.closeDoneLocked()
}

// 要求持有p.mu。
func (p *http2pipe) closeDoneLocked() {
	if p.donec == nil {
		return
	}
	// 如果未关闭，则关闭。这不太有意思，因为我们总是在关门时按住p.mu。
	select {
	case <-p.donec:
	default:
		close(p.donec)
	}
}

// Err返回BreakWithError或CloseWithError首先设置的错误（如果有）。
func (p *http2pipe) Err() error {
	p.mu.Lock()
	defer p.mu.Unlock()
	if p.breakErr != nil {
		return p.breakErr
	}
	return p.err
}

// Done返回一个在管道关闭时关闭的通道
// with CLOSEWERROR。
func (p *http2pipe) Done() <-chan struct{} {
	p.mu.Lock()
	defer p.mu.Unlock()
	if p.donec == nil {
		p.donec = make(chan struct{})
		if p.err != nil || p.breakErr != nil {
			// 已遇到错误。
			p.closeDoneLocked()
		}
	}
	return p.donec
}

const (
	http2prefaceTimeout         = 10 * time.Second
	http2firstSettingsTimeout   = 2 * time.Second // 无论如何都应该带着序言飞行
	http2handlerChunkWriteSize  = 4 << 10
	http2defaultMaxStreams      = 250 // TODO:按照GFE的样子做100？
	http2maxQueuedControlFrames = 10000
)

var (
	http2errClientDisconnected = errors.New("client disconnected")
	http2errClosedBody         = errors.New("body closed by handler")
	http2errHandlerComplete    = errors.New("http2: request body closed due to handler exiting")
	http2errStreamClosed       = errors.New("http2: stream closed")
)

var http2responseWriterStatePool = sync.Pool{
	New: func() interface{} {
		rws := &http2responseWriterState{}
		rws.bw = bufio.NewWriterSize(http2chunkWriter{rws}, http2handlerChunkWriteSize)
		return rws
	},
}

// 测试挂钩。
var (
	http2testHookOnConn        func()
	http2testHookGetServerConn func(*http2serverConn)
	http2testHookOnPanicMu     *sync.Mutex // nil，测试除外
	http2testHookOnPanic       func(sc *http2serverConn, panicVal interface{}) (rePanic bool)
)

// 服务器是HTTP/2服务器。
type http2Server struct {
	// MaxHandlers限制http的数量。Handler ServeHTTP goroutines 
	// 一次可以在所有连接上运行。
	// 负或零无限制。
	// TODO:实现
	MaxHandlers int

	// MaxConcurrentStreams可选地指定每个客户端在
	// 并发流的数量。这与http的数量无关。Handler goroutines 
	// 时间打开的
	// 它可能在全局处于活动状态，即MaxHandler。
	// 如果为零，根据HTTP/2规范的建议，MaxConcurrentStreams默认值至少为100。
	MaxConcurrentStreams uint32

	// MaxReadFrameSize可选指定此服务器愿意读取的最大帧
	// 。有效值介于
	// 16k和16M（含16M）之间。如果为零或无效，则使用
	// 默认值。
	MaxReadFrameSize uint32

	// PermittprohibitedCipherSuite，如果为true，则允许使用HTTP/2规范禁止的密码套件。
	PermitProhibitedCipherSuites bool

	// IdleTimeout指定空闲客户端应在多长时间内使用GOAWAY框架关闭。PING帧不被视为用于IdleTimeout的
	// 活动。
	IdleTimeout time.Duration

	// MaxUploadBufferPerConnection是每个连接的初始流
	// 控制窗口的大小。HTTP/2规范不允许小于65535或大于2^32-1。
	// 如果该值超出此范围，将使用默认值
	// 代替。
	MaxUploadBufferPerConnection int32

	// MaxUploadBufferPerStream是每个流的初始流控制
	// 窗口的大小。HTTP/2规范不允许
	// 大于2^32-1。如果该值为零或大于
	// 最大值，则将使用默认值。
	MaxUploadBufferPerStream int32

	// NewWriteScheduler为连接构造写调度程序。
	// 如果为nil，则选择默认计划程序。
	NewWriteScheduler func() http2WriteScheduler

	// CountError，如果非nil，则在HTTP/2服务器错误上调用。
	// 其目的是增加一个用于监控的度量，例如
	// 作为expvar或Prometheus度量。
	// 错误类型仅由ASCII字字符组成。
	CountError func(errType string)

	// 内部状态。这是一个指针（而不是直接嵌入的）
	// 这样我们就不会在这个结构中嵌入互斥，这将使
	// 结构不可复制，这可能会破坏一些调用方。
	state *http2serverInternalState
}

func (s *http2Server) initialConnRecvWindowSize() int32 {
	if s.MaxUploadBufferPerConnection > http2initialWindowSize {
		return s.MaxUploadBufferPerConnection
	}
	return 1 << 20
}

func (s *http2Server) initialStreamRecvWindowSize() int32 {
	if s.MaxUploadBufferPerStream > 0 {
		return s.MaxUploadBufferPerStream
	}
	return 1 << 20
}

func (s *http2Server) maxReadFrameSize() uint32 {
	if v := s.MaxReadFrameSize; v >= http2minMaxFrameSize && v <= http2maxFrameSize {
		return v
	}
	return http2defaultMaxReadFrameSize
}

func (s *http2Server) maxConcurrentStreams() uint32 {
	if v := s.MaxConcurrentStreams; v > 0 {
		return v
	}
	return http2defaultMaxStreams
}

// maxQueuedControlFrames是在
// 设置、PING和RST_流。
// 关闭连接以防止内存耗尽攻击之前，将排队等待写入的最大控制帧数，如
func (s *http2Server) maxQueuedControlFrames() int {
	// TODO:如果有人要求，请添加一个服务器字段，并记住定义
	// 负值的行为。
	return http2maxQueuedControlFrames
}

type http2serverInternalState struct {
	mu          sync.Mutex
	activeConns map[*http2serverConn]struct{}
}

func (s *http2serverInternalState) registerConn(sc *http2serverConn) {
	if s == nil {
		return // 如果使用服务器时未调用ConfigureServer 
	}
	s.mu.Lock()
	s.activeConns[sc] = struct{}{}
	s.mu.Unlock()
}

func (s *http2serverInternalState) unregisterConn(sc *http2serverConn) {
	if s == nil {
		return // 如果使用服务器时未调用ConfigureServer 
	}
	s.mu.Lock()
	delete(s.activeConns, sc)
	s.mu.Unlock()
}

func (s *http2serverInternalState) startGracefulShutdown() {
	if s == nil {
		return // 如果使用服务器时未调用ConfigureServer 
	}
	s.mu.Lock()
	for sc := range s.activeConns {
		sc.startGracefulShutdown()
	}
	s.mu.Unlock()
}

// ConfigureServer为net/HTTP服务器添加了HTTP/2支持。
// 
// 配置配置可能为零。
// 
// 必须在s开始服务之前调用ConfigureServer。
func http2ConfigureServer(s *Server, conf *http2Server) error {
	if s == nil {
		panic("nil *http.Server")
	}
	if conf == nil {
		conf = new(http2Server)
	}
	conf.state = &http2serverInternalState{activeConns: make(map[*http2serverConn]struct{})}
	if h1, h2 := s, conf; h2.IdleTimeout == 0 {
		if h1.IdleTimeout != 0 {
			h2.IdleTimeout = h1.IdleTimeout
		} else {
			h2.IdleTimeout = h1.ReadTimeout
		}
	}
	s.RegisterOnShutdown(conf.state.startGracefulShutdown)

	if s.TLSConfig == nil {
		s.TLSConfig = new(tls.Config)
	} else if s.TLSConfig.CipherSuites != nil && s.TLSConfig.MinVersion < tls.VersionTLS13 {
		// 如果他们已经提供了TLS 1.0–1.2密码套件列表，如果缺少ECDHE_RSA_WITH_AES_128_GCM_SHA256或
		// 错误。
		// ECDHE_ECDSA_WITH_AES_128_GCM_SHA256，则返回一个
		haveRequired := false
		for _, cs := range s.TLSConfig.CipherSuites {
			switch cs {
			case tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
				// 替代MTI密码不鼓励仅使用ECDSA的服务器。
				// 请参见http:
				tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:
				haveRequired = true
			}
		}
		if !haveRequired {
			return fmt.Errorf("http2: TLSConfig.CipherSuites is missing an HTTP/2-required AES_128_GCM_SHA256 cipher (need at least one of TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 or TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256)")
		}
	}

	// 注意：未将MinVersion设置为tls。VersionTLS12，
	// 因为我们不想干扰用户服务器上的HTTP/1.1流量
	// 。一旦
	// 我们接受一个连接，我们将强制执行TLS 1.2。理想情况下，这应该在下一个proto选择过程中完成，但是使用TLS<1.2和
	// HTTP/2仍然是客户端的错误。

	s.TLSConfig.PreferServerCipherSuites = true

	if !http2strSliceContains(s.TLSConfig.NextProtos, http2NextProtoTLS) {
		s.TLSConfig.NextProtos = append(s.TLSConfig.NextProtos, http2NextProtoTLS)
	}
	if !http2strSliceContains(s.TLSConfig.NextProtos, "http/1.1") {
		s.TLSConfig.NextProtos = append(s.TLSConfig.NextProtos, "http/1.1")
	}

	if s.TLSNextProto == nil {
		s.TLSNextProto = map[string]func(*Server, *tls.Conn, Handler){}
	}
	protoHandler := func(hs *Server, c *tls.Conn, h Handler) {
		if http2testHookOnConn != nil {
			http2testHookOnConn()
		}
		// TLSNextProto接口早于上下文，因此
		// net/http包通过处理程序上的导出但未经广告的
		// 基本上下文。这只供内部
		// 方法传递其每个连接
		// net/http<=>http2使用。
		var ctx context.Context
		type baseContexter interface {
			BaseContext() context.Context
		}
		if bc, ok := h.(baseContexter); ok {
			ctx = bc.BaseContext()
		}
		conf.ServeConn(c, &http2ServeConnOpts{
			Context:    ctx,
			Handler:    h,
			BaseConfig: hs,
		})
	}
	s.TLSNextProto[http2NextProtoTLS] = protoHandler
	return nil
}

// serveconopts是服务器的选项。servecon方法。
type http2ServeConnOpts struct {
	// 上下文是要使用的基本上下文。
	// 如果为零，则为上下文。使用背景。
	Context context.Context

	// BaseConfig可选地为值设置基本配置
	// 。如果为nil，则使用默认值。
	BaseConfig *Server

	// 处理程序指定用于处理
	// 请求的处理程序。如果为nil，则为BaseConfig。使用了Handler。如果是BaseConfig 
	// 或BaseConfig。处理程序是nil，http。使用DefaultServeMux。
	Handler Handler
}

func (o *http2ServeConnOpts) context() context.Context {
	if o != nil && o.Context != nil {
		return o.Context
	}
	return context.Background()
}

func (o *http2ServeConnOpts) baseConfig() *Server {
	if o != nil && o.BaseConfig != nil {
		return o.BaseConfig
	}
	return new(Server)
}

func (o *http2ServeConnOpts) handler() Handler {
	if o != nil {
		if o.Handler != nil {
			return o.Handler
		}
		if o.BaseConfig != nil && o.BaseConfig.Handler != nil {
			return o.BaseConfig.Handler
		}
	}
	return DefaultServeMux
}

// ServeCon在提供的连接上提供HTTP/2请求，并且
// 阻塞，直到连接不再可读为止。
// 
// Servecon开始讲HTTP/2，假设c没有任何读写操作。它编写初始设置框架，并希望
// 能够从
// 客户端读取前言和设置框架。如果c有一个像a*tls这样的ConnectionState方法。Conn，
// 连接状态用于验证TLS密码套件并设置
// 请求。处理程序中的TLS字段。
// 
// Servecon本身不支持h2c。任何h2c支持都必须是
// 在提供适当行为的网络方面实施。Conn.
// 
// opts参数是可选的。如果为nil，则使用默认值。
func (s *http2Server) ServeConn(c net.Conn, opts *http2ServeConnOpts) {
	baseCtx, cancel := http2serverConnBaseContext(c, opts)
	defer cancel()

	sc := &http2serverConn{
		srv:                         s,
		hs:                          opts.baseConfig(),
		conn:                        c,
		baseCtx:                     baseCtx,
		remoteAddrStr:               c.RemoteAddr().String(),
		bw:                          http2newBufferedWriter(c),
		handler:                     opts.handler(),
		streams:                     make(map[uint32]*http2stream),
		readFrameCh:                 make(chan http2readFrameResult),
		wantWriteFrameCh:            make(chan http2FrameWriteRequest, 8),
		serveMsgCh:                  make(chan interface{}, 8),
		wroteFrameCh:                make(chan http2frameWriteResult, 1), // 缓冲；一次写入式发送异步
		bodyReadCh:                  make(chan http2bodyReadMsg),         // 缓冲无论哪种方式都无关紧要
		doneServing:                 make(chan struct{}),
		clientMaxStreams:            math.MaxUint32, // 第6.5.2节：“最初，这个值没有限制”
		advMaxStreams:               s.maxConcurrentStreams(),
		initialStreamSendWindowSize: http2initialWindowSize,
		maxFrameSize:                http2initialMaxFrameSize,
		headerTableSize:             http2initialHeaderTableSize,
		serveG:                      http2newGoroutineLock(),
		pushEnabled:                 true,
	}

	s.state.registerConn(sc)
	defer s.state.unregisterConn(sc)

	// net/http包设置
	// http的写入截止日期。服务器在TLS握手过程中写出来，但
	// 会在设定的最后期限内将连接传递给我们。
	// 在serverConn中为每个流设置写入截止日期。新闻流。
	// 解除网络。康涅狄格在这里写最后期限。
	if sc.hs.WriteTimeout != 0 {
		sc.conn.SetWriteDeadline(time.Time{})
	}

	if s.NewWriteScheduler != nil {
		sc.writeSched = s.NewWriteScheduler()
	} else {
		sc.writeSched = http2NewRandomWriteScheduler()
	}

	// 这些从RFC指定的默认值开始。如果有更高的
	// 流入配置值，则在发送设置后不久发送
	// 窗口更新时，该值将被更新。
	sc.flow.add(http2initialWindowSize)
	sc.inflow.add(http2initialWindowSize)
	sc.hpackEncoder = hpack.NewEncoder(&sc.headerWriteBuf)

	fr := http2NewFramer(sc.bw, c)
	if s.CountError != nil {
		fr.countError = s.CountError
	}
	fr.ReadMetaHeaders = hpack.NewDecoder(http2initialHeaderTableSize, nil)
	fr.MaxHeaderListSize = sc.maxHeaderListSize()
	fr.SetMaxReadFrameSize(s.maxReadFrameSize())
	sc.framer = fr

	if tc, ok := c.(http2connectionStater); ok {
		sc.tlsState = new(tls.ConnectionState)
		*sc.tlsState = tc.ConnectionState()
		// 9.2 TLS功能的使用
		// HTTP/2在TLS上的实现必须使用TLS 
		// 1.2或更高版本，并受本节描述的功能集
		// 和密码套件的限制。由于
		// 实施限制，可能不会导致TLS协商失败。端点必须
		// 立即终止一个HTTP/2连接，如果
		// 不满足
		// 本节中描述的TLS要求，并且存在一个类型不充分的连接错误（第
		// 5.4.1节）。
		if sc.tlsState.Version < tls.VersionTLS12 {
			sc.rejectConn(http2ErrCodeInadequateSecurity, "TLS version too low")
			return
		}

		if sc.tlsState.ServerName == "" {
			// 客户端必须使用SNI，但我们不再强制执行，因为它在开发过程中连接到裸IP地址时会导致问题。
			// 
			// TODO:可选执行？或者在我们收到
			// 一个新请求时强制执行，并验证服务器名是否与：权限匹配？
			// 但这可能排除了代理情况。
			// 
			// 所以现在，在这里什么也不要做。
		}

		if !s.PermitProhibitedCipherSuites && http2isBadCipher(sc.tlsState.CipherSuite) {
			// “如果协商了其中一个
			// （第5.4.1节）。”我们选择这个。在我看来，这里的规范是弱
			// 禁止的密码套件，则端点可能会选择生成类型为不充分安全的连接错误
			// 的。它还表示，双方必须至少支持
			// TLS_ECDHE_RSA_与_AES_128_GCM_SHA256，因此这里没有
			// 。如果我们真的必须这样做，我们可以稍后在服务器上允许
			// /“AllowInSecureWeakChipers”选项。
			// 让我们先看看结果如何。
			sc.rejectConn(http2ErrCodeInadequateSecurity, fmt.Sprintf("Prohibited TLS 1.2 Cipher Suite: %x", sc.tlsState.CipherSuite))
			return
		}
	}

	if hook := http2testHookGetServerConn; hook != nil {
		hook(sc)
	}
	sc.serve()
}

func http2serverConnBaseContext(c net.Conn, opts *http2ServeConnOpts) (ctx context.Context, cancel func()) {
	ctx, cancel = context.WithCancel(opts.context())
	ctx = context.WithValue(ctx, LocalAddrContextKey, c.LocalAddr())
	if hs := opts.baseConfig(); hs != nil {
		ctx = context.WithValue(ctx, ServerContextKey, hs)
	}
	return
}

func (sc *http2serverConn) rejectConn(err http2ErrCode, debug string) {
	sc.vlogf("http2: server rejecting conn: %v, %s", err, debug)
	// 忽略错误。还是挂了吧。
	sc.framer.WriteGoAway(0, err, []byte(debug))
	sc.bw.Flush()
	sc.conn.Close()
}

type http2serverConn struct {
	// 不可变：
	srv              *http2Server
	hs               *Server
	conn             net.Conn
	bw               *http2bufferedWriter // 写入conn 
	handler          Handler
	baseCtx          context.Context
	framer           *http2Framer
	doneServing      chan struct{}               // 服务器连接时关闭。服务端
	readFrameCh      chan http2readFrameResult   // 由ServeConn编写。readFrames 
	wantWriteFrameCh chan http2FrameWriteRequest // 来自处理程序->服务
	wroteFrameCh     chan http2frameWriteResult  // 来自writeFrameAsync->服务，tickles more frame写入
	bodyReadCh       chan http2bodyReadMsg       // 从处理程序->服务
	serveMsgCh       chan interface{}            // 发送到服务循环上/在服务循环上运行的杂项消息和代码
	flow             http2flow                   // 连接范围（非特定流）出站流控制
	inflow           http2flow                   // 连接范围内的入站流控制
	tlsState         *tls.ConnectionState        // 由所有处理程序共享，像net/http 
	remoteAddrStr    string
	writeSched       http2WriteScheduler

	// 下面的所有内容都属于服务循环；使用serveG。check（）：
	serveG                      http2goroutineLock // 用于验证函数是否在服务中（）
	pushEnabled                 bool
	sawFirstSettings            bool // 在序言
	needToSendSettingsAck       bool
	unackedSettings             int    // 之后获得了初始设置帧。我们在没有确认的情况下发送了多少设置？
	queuedControlFrames         int    // 写队列中的控制帧
	clientMaxStreams            uint32 // 设置来自客户端的最大并发流（我们的推送承诺限制）
	advMaxStreams               uint32 // 我们的设置\u最大并发流广告客户端
	curClientStreams            uint32 // 客户端发起的开放流数
	curPushedStreams            uint32 // 服务器发起的开放流数
	maxClientStreamID           uint32 // /从客户端看到的最大值（奇数），如果没有客户端请求，则为0 
	maxPushPromiseID            uint32 // 上次推送承诺的ID（偶数），如果没有推送，则为0。
	streams                     map[uint32]*http2stream
	initialStreamSendWindowSize int32
	maxFrameSize                int32
	headerTableSize             uint32
	peerMaxHeaderListSize       uint32            // 0表示未知（默认）
	canonHeader                 map[string]string // http2小写->Go规范大小写
	writingFrame                bool              // 开始编写帧（在服务goroutine或单独的）
	writingFrameAsync           bool              // 在自己的goroutine上启动了一个帧，但在wroteFrameCh 
	needsFrameFlush             bool              // 上一次帧写入不是刷新
	inGoAway                    bool              // 我们已经开始或发送GOAWAY 
	inFrameScheduleLoop         bool              // 我们是否在scheduleFrameWrite循环
	needToSendGoAway            bool              // 我们需要计划一个GOAWAY框架写入
	goAwayCode                  http2ErrCode
	shutdownTimer               *time.Timer // nil直到使用
	idleTimer                   *time.Timer // nil如果未使用

	// 由writeFrameAsync goroutine拥有：
	headerWriteBuf bytes.Buffer
	hpackEncoder   *hpack.Encoder

	// 由startGracefulShutdown使用。
	shutdownOnce sync.Once
}

func (sc *http2serverConn) maxHeaderListSize() uint32 {
	n := sc.hs.MaxHeaderBytes
	if n <= 0 {
		n = DefaultMaxHeaderBytes
	}
	// http2的计数单位略有不同，每对包含32字节。
	// 以net/http为例。服务器值，并将其填充一点，假设有10个头。
	const perFieldOverhead = 32 // 根据http2规范
	const typicalHeaders = 10   // 保守型
	return uint32(n + typicalHeaders*perFieldOverhead)
}

func (sc *http2serverConn) curOpenStreams() uint32 {
	sc.serveG.check()
	return sc.curClientStreams + sc.curPushedStreams
}

// 流表示流。这是
// 服务goroutine所需的最小元数据。大多数实际的流状态都属于
// http。Handler在responseWriter中的goroutine。由于
// responseWriter的responseWriterState在
// 处理程序的末尾被循环使用，因此此结构故意没有指向
// *responseWriter{，State}本身的指针，因为处理程序的结尾为零，表示
// responseWriter的State字段。
type http2stream struct {
	// 不可变：
	sc        *http2serverConn
	id        uint32
	body      *http2pipe       // 如果需要数据帧，则非零
	cw        http2closeWaiter // 关闭等待流转换为关闭状态
	ctx       context.Context
	cancelCtx func()

	// 由serverConn的服务循环拥有：
	bodyBytes        int64     // 到目前为止看到的正文字节
	declBodyBytes    int64     // 如果未声明
	flow             http2flow // 限制从处理程序到客户端的写入
	inflow           http2flow // 允许客户向我们发送/etc 
	state            http2streamState
	resetQueued      bool        // RST_流排队等待写入；由sc.resetStream 
	gotTrailerHeader bool        // 查看拖车的标题帧
	wroteHeaders     bool        // 我们是否写入了标题（非状态100）
	writeDeadline    *time.Timer // 如果未使用

	trailer    Header // 则为零累积拖车
	reqTrailer Header // 处理程序的请求。拖车
}

func (sc *http2serverConn) Framer() *http2Framer { return sc.framer }

func (sc *http2serverConn) CloseConn() error { return sc.conn.Close() }

func (sc *http2serverConn) Flush() error { return sc.bw.Flush() }

func (sc *http2serverConn) HeaderEncoder() (*hpack.Encoder, *bytes.Buffer) {
	return sc.hpackEncoder, &sc.headerWriteBuf
}

func (sc *http2serverConn) state(streamID uint32) (http2streamState, *http2stream) {
	sc.serveG.check()
	// http:
	if st, ok := sc.streams[streamID]; ok {
		return st.state, st
	}
	// “首次使用新的流标识符将隐式关闭“空闲”中的所有
	// “可能已由
	// 使用较低值流标识符的对等方启动的状态。例如，如果
	// 一个客户端在流7上发送了一个头帧，而从未在流5上发送过
	// 帧，那么流5在发送或接收流7的第一个帧时会转换为“关闭”
	// 状态。”
	if streamID%2 == 1 {
		if streamID <= sc.maxClientStreamID {
			return http2stateClosed, nil
		}
	} else {
		if streamID <= sc.maxPushPromiseID {
			return http2stateClosed, nil
		}
	}
	return http2stateIdle, nil
}

// setConnState调用此连接的net/http ConnState钩子（如果已配置）。
// 注意，net/http包为我们提供StateNew和StateClosed。
// 目前还没有针对状态劫持或劫持HTTP/2连接的计划。
func (sc *http2serverConn) setConnState(state ConnState) {
	if sc.hs.ConnState != nil {
		sc.hs.ConnState(sc.conn, state)
	}
}

func (sc *http2serverConn) vlogf(format string, args ...interface{}) {
	if http2VerboseLogs {
		sc.logf(format, args...)
	}
}

func (sc *http2serverConn) logf(format string, args ...interface{}) {
	if lg := sc.hs.ErrorLog; lg != nil {
		lg.Printf(format, args...)
	} else {
		log.Printf(format, args...)
	}
}

// errno返回v的基础uintpttr，否则返回0。
// 
// TODO:一旦http2可以使用build 
// 标记，就删除这个助手函数。请参阅ISClosedConnector中的注释。
func http2errno(v error) uintptr {
	if rv := reflect.ValueOf(v); rv.Kind() == reflect.Uintptr {
		return uintptr(rv.Uint())
	}
	return 0
}

// IsClosedConnector报告错误是否是由于使用关闭的
// 网络连接而导致的错误。
func http2isClosedConnError(err error) bool {
	if err == nil {
		return false
	}

	// TODO:删除此字符串搜索，更像下面的Windows 
	// case。这可能涉及修改标准库
	// 以返回更好的错误类型。
	str := err.Error()
	if strings.Contains(str, "use of closed network connection") {
		return true
	}

	// TODO（bradfitz）：x/tools/cmd/bundle实际上不支持
	// build标记，所以我无法在windows上制作http2。使用
	// Windows特定的文件。解决这个问题，并将其移动，一旦我们
	// 有办法将其捆绑到std的net/http中。
	if runtime.GOOS == "windows" {
		if oe, ok := err.(*net.OpError); ok && oe.Op == "read" {
			if se, ok := oe.Err.(*os.SyscallError); ok && se.Syscall == "wsarecv" {
				const WSAECONNABORTED = 10053
				const WSAECONNRESET = 10054
				if n := http2errno(se.Err); n == WSAECONNRESET || n == WSAECONNABORTED {
					return true
				}
			}
		}
	}
	return false
}

func (sc *http2serverConn) condlogf(err error, format string, args ...interface{}) {
	if err == nil {
		return
	}
	if err == io.EOF || err == io.ErrUnexpectedEOF || http2isClosedConnError(err) || err == http2errPrefaceTimeout {
		// 无聊，预期错误。
		sc.vlogf(format, args...)
	} else {
		sc.logf(format, args...)
	}
}

func (sc *http2serverConn) canonicalHeader(v string) string {
	sc.serveG.check()
	http2buildCommonHeaderMapsOnce()
	cv, ok := http2commonCanonHeader[v]
	if ok {
		return cv
	}
	cv, ok = sc.canonHeader[v]
	if ok {
		return cv
	}
	if sc.canonHeader == nil {
		sc.canonHeader = make(map[string]string)
	}
	cv = CanonicalHeaderKey(v)
	// maxCachedCanonicalHeaders是对canonHeader缓存中
	// 条目的数量的任意选择限制。这应该大于对等方可能发送的唯一、不常见的头密钥的数量
	// 而不是
	// 高到允许不合理的内存使用，如果对等方发送无限的
	// 唯一头密钥的数量。
	const maxCachedCanonicalHeaders = 32
	if len(sc.canonHeader) < maxCachedCanonicalHeaders {
		sc.canonHeader[v] = cv
	}
	return cv
}

type http2readFrameResult struct {
	f   http2Frame // 在调用readMore之前有效
	err error

	// 保留f，则应调用readMore。readMore之后，f无效，可以读取更多帧。
	readMore func()
}

// readFrames是读取传入帧的循环。
// 一次只读取一个帧，阻塞直到
// 消费者处理完该帧。
// 它在自己的goroutine上运行。
func (sc *http2serverConn) readFrames() {
	gate := make(http2gate)
	gateDone := gate.Done
	for {
		f, err := sc.framer.ReadFrame()
		select {
		case sc.readFrameCh <- http2readFrameResult{f, err, gateDone}:
		case <-sc.doneServing:
			return
		}
		select {
		case <-gate:
		case <-sc.doneServing:
			return
		}
		if http2terminalReadFrameError(err) {
			return
		}
	}
}

// frameWriteResult是从writeFrameAsync传递到serve goroutine的消息。
type http2frameWriteResult struct {
	_   http2incomparable
	wr  http2FrameWriteRequest // 写入（或尝试写入）的内容
	err error                  // WriteName调用的结果
}

// writeFrameAsync在其自己的goroutine中运行，并写入单帧
// 完成后报告。
// 每个
// serverConn最多一个goroutine一次可以运行writeFrameAsync。
func (sc *http2serverConn) writeFrameAsync(wr http2FrameWriteRequest) {
	err := wr.write.writeFrame(sc)
	sc.wroteFrameCh <- http2frameWriteResult{wr: wr, err: err}
}

func (sc *http2serverConn) closeAllStreamsOnConnClose() {
	sc.serveG.check()
	for _, st := range sc.streams {
		sc.closeStream(st, http2errClientDisconnected)
	}
}

func (sc *http2serverConn) stopShutdownTimer() {
	sc.serveG.check()
	if t := sc.shutdownTimer; t != nil {
		t.Stop()
	}
}

func (sc *http2serverConn) notePanic() {
	// 注意：这是给serverConn的。服务恐慌，而不是http。处理程序代码。
	if http2testHookOnPanicMu != nil {
		http2testHookOnPanicMu.Lock()
		defer http2testHookOnPanicMu.Unlock()
	}
	if http2testHookOnPanic != nil {
		if e := recover(); e != nil {
			if http2testHookOnPanic(sc, e) {
				panic(e)
			}
		}
	}
}

func (sc *http2serverConn) serve() {
	sc.serveG.check()
	defer sc.notePanic()
	defer sc.conn.Close()
	defer sc.closeAllStreamsOnConnClose()
	defer sc.stopShutdownTimer()
	defer close(sc.doneServing) // 取消阻止试图发送

	if http2VerboseLogs {
		sc.vlogf("http2: server connection from %v on %p", sc.conn.RemoteAddr(), sc.hs)
	}

	sc.writeFrame(http2FrameWriteRequest{
		write: http2writeSettings{
			{http2SettingMaxFrameSize, sc.srv.maxReadFrameSize()},
			{http2SettingMaxConcurrentStreams, sc.advMaxStreams},
			{http2SettingMaxHeaderListSize, sc.maxHeaderListSize()},
			{http2SettingInitialWindowSize, uint32(sc.srv.initialStreamRecvWindowSize())},
		},
	})
	sc.unackedSettings++

	// 的处理程序。每个连接都以Initialize窗口标记开始。
	// 如果配置了更高的值，我们会添加更多令牌。
	if diff := sc.srv.initialConnRecvWindowSize() - http2initialWindowSize; diff > 0 {
		sc.sendWindowUpdate(nil, int(diff))
	}

	if err := sc.readPreface(); err != nil {
		sc.condlogf(err, "http2: server: error reading preface from client %v: %v", sc.conn.RemoteAddr(), err)
		return
	}
	// 现在我们已经有了序言，让我们离开
	// “StateNew”状态。不过，我们不能直接进入空闲状态。
	// Active表示我们读取一些数据并预期一个请求。我们将
	// 当我们得到一个标题帧时，再做一个活动。
	sc.setConnState(StateActive)
	sc.setConnState(StateIdle)

	if sc.srv.IdleTimeout != 0 {
		sc.idleTimer = time.AfterFunc(sc.srv.IdleTimeout, sc.onIdleTimer)
		defer sc.idleTimer.Stop()
	}

	go sc.readFrames() // 由DEBER sc.conn关闭。上面的Close 

	settingsTimer := time.AfterFunc(http2firstSettingsTimeout, sc.onSettingsTimer)
	defer settingsTimer.Stop()

	loopNum := 0
	for {
		loopNum++
		select {
		case wr := <-sc.wantWriteFrameCh:
			if se, ok := wr.write.(http2StreamError); ok {
				sc.resetStream(se)
				break
			}
			sc.writeFrame(wr)
		case res := <-sc.wroteFrameCh:
			sc.wroteFrame(res)
		case res := <-sc.readFrameCh:
			// 在从客户端读取新帧之前处理所有已写入的帧，因为
			// 已写入的帧可能已触发要启动的新流。
			if sc.writingFrameAsync {
				select {
				case wroteRes := <-sc.wroteFrameCh:
					sc.wroteFrame(wroteRes)
				default:
				}
			}
			if !sc.processFrameFromReader(res) {
				return
			}
			res.readMore()
			if settingsTimer != nil {
				settingsTimer.Stop()
				settingsTimer = nil
			}
		case m := <-sc.bodyReadCh:
			sc.noteBodyRead(m.st, m.n)
		case msg := <-sc.serveMsgCh:
			switch v := msg.(type) {
			case func(int):
				v(loopNum) // 用于测试
			case *http2serverMessage:
				switch v {
				case http2settingsTimerMsg:
					sc.logf("timeout waiting for SETTINGS frames from %v", sc.conn.RemoteAddr())
					return
				case http2idleTimerMsg:
					sc.vlogf("connection is idle")
					sc.goAway(http2ErrCodeNo)
				case http2shutdownTimerMsg:
					sc.vlogf("GOAWAY close timer fired; closing conn from %v", sc.conn.RemoteAddr())
					return
				case http2gracefulShutdownMsg:
					sc.startGracefulShutdownInternal()
				default:
					panic("unknown timer")
				}
			case *http2startPushRequest:
				sc.startPush(v)
			default:
				panic(fmt.Sprintf("unexpected type %T", v))
			}
		}

		// 如果对等方导致我们生成大量控制帧，
		// 但没有从我们这里读取它们，则假设它们试图让我们
		// 内存耗尽。
		if sc.queuedControlFrames > sc.srv.maxQueuedControlFrames() {
			sc.vlogf("http2: too many control frames in send queue, closing connection")
			return
		}

		// 发送GOAWAY后启动关机计时器。发送GOAWAY 
		// 时没有错误代码（正常关机），在
		// 所有打开的流完成之前不要启动计时器。
		sentGoAway := sc.inGoAway && !sc.needToSendGoAway && !sc.writingFrame
		gracefulShutdownComplete := sc.goAwayCode == http2ErrCodeNo && sc.curOpenStreams() == 0
		if sentGoAway && sc.shutdownTimer == nil && (sc.goAwayCode != http2ErrCodeNo || gracefulShutdownComplete) {
			sc.shutDownIn(http2goAwayTimeout)
		}
	}
}

func (sc *http2serverConn) awaitGracefulShutdown(sharedCh <-chan struct{}, privateCh chan struct{}) {
	select {
	case <-sc.doneServing:
	case <-sharedCh:
		close(privateCh)
	}
}

type http2serverMessage int

// 发送到serveMsgCh的消息值。
var (
	http2settingsTimerMsg    = new(http2serverMessage)
	http2idleTimerMsg        = new(http2serverMessage)
	http2shutdownTimerMsg    = new(http2serverMessage)
	http2gracefulShutdownMsg = new(http2serverMessage)
)

func (sc *http2serverConn) onSettingsTimer() { sc.sendServeMsg(http2settingsTimerMsg) }

func (sc *http2serverConn) onIdleTimer() { sc.sendServeMsg(http2idleTimerMsg) }

func (sc *http2serverConn) onShutdownTimer() { sc.sendServeMsg(http2shutdownTimerMsg) }

func (sc *http2serverConn) sendServeMsg(msg interface{}) {
	sc.serveG.checkNotOn() // NOT 
	select {
	case sc.serveMsgCh <- msg:
	case <-sc.doneServing:
	}
}

var http2errPrefaceTimeout = errors.New("timeout waiting for client preface")

// ReadPreforce读取来自对等方的ClientPreforce问候语，或
// 在超时时返回errPrefaceTimeout，如果问候语
// 无效，则返回错误。
func (sc *http2serverConn) readPreface() error {
	errc := make(chan error, 1)
	go func() {
		// 阅读客户端前言
		buf := make([]byte, len(http2ClientPreface))
		if _, err := io.ReadFull(sc.conn, buf); err != nil {
			errc <- err
		} else if !bytes.Equal(buf, http2clientPreface) {
			errc <- fmt.Errorf("bogus greeting %q", buf)
		} else {
			errc <- nil
		}
	}()
	timer := time.NewTimer(http2prefaceTimeout) // TODO:可在*服务器上配置？
	defer timer.Stop()
	select {
	case <-timer.C:
		return http2errPrefaceTimeout
	case err := <-errc:
		if err == nil {
			if http2VerboseLogs {
				sc.vlogf("http2: server: client %v said hello", sc.conn.RemoteAddr())
			}
		}
		return err
	}
}

var http2errChanPool = sync.Pool{
	New: func() interface{} { return make(chan error, 1) },
}

var http2writeDataPool = sync.Pool{
	New: func() interface{} { return new(http2writeData) },
}

// writeDataFromHandler从
// 给定流上的处理程序写入数据响应帧。
func (sc *http2serverConn) writeDataFromHandler(stream *http2stream, data []byte, endStream bool) error {
	ch := http2errChanPool.Get().(chan error)
	writeArg := http2writeDataPool.Get().(*http2writeData)
	*writeArg = http2writeData{stream.id, data, endStream}
	err := sc.writeFrameFromHandler(http2FrameWriteRequest{
		write:  writeArg,
		stream: stream,
		done:   ch,
	})
	if err != nil {
		return err
	}
	var frameWriteDone bool // 帧写入已完成（成功与否）
	select {
	case err = <-ch:
		frameWriteDone = true
	case <-sc.doneServing:
		return http2errClientDisconnected
	case <-stream.cw:
		// 如果ch和stream都已完成。cw已准备就绪（在http.Handler结束后的最后一次写入时，可能会发生
		// 的情况），更喜欢写入结果。否则这个
		// 可能就是我们成功地关闭了这个流。
		// writeFrameAsync和serve goroutines保证了
		// ch发送将在流之前发生。cw 
		// 关闭。
		select {
		case err = <-ch:
			frameWriteDone = true
		default:
			return http2errStreamClosed
		}
	}
	http2errChanPool.Put(ch)
	if frameWriteDone {
		http2writeDataPool.Put(writeArg)
	}
	return err
}

// writeFrameFromHandler将wr发送到sc.wantWriteFrameCh，但如果连接已断开，则中止
// 。
// 
// 这不能从serve goroutine本身运行，否则它可能会导致写入sc.wantWriteFrameCh的死锁（这只是略微缓冲了
// 并由serve本身读取）。如果你在发球
// goroutine，请拨打WriteName。
func (sc *http2serverConn) writeFrameFromHandler(wr http2FrameWriteRequest) error {
	sc.serveG.checkNotOn() // 不是
	select {
	case sc.wantWriteFrameCh <- wr:
		return nil
	case <-sc.doneServing:
		// 发球循环消失。
		// 客户端已关闭与服务器的连接。
		return http2errClientDisconnected
	}
}

// writeFrame计划写入一个帧，如果没有任何内容，则发送该帧。
// 
// 这里没有后退（发球路线从不阻塞）。这是
// http。阻塞的处理程序，等待其前一帧到达
// 连接到导线
// 
// 如果您不在serve GOROUTE上，请改用writeFrameFromHandler。
func (sc *http2serverConn) writeFrame(wr http2FrameWriteRequest) {
	sc.serveG.check()

	// 如果为真，则不会写入wr，也不会写入wr。不会发出完成的信号。
	var ignoreWrite bool

	// 我们不允许在封闭流上写入帧。RFC 7540第
	// 5.1.1节说：“端点不得在
	// 封闭流上发送优先级以外的帧。”我们的服务器从不发送优先级，因此异常
	// 不适用。
	// 
	// 当流的处理程序
	// 仍在运行时，serverConn可能会关闭打开的流。例如，当服务器
	// 从客户端接收到错误数据时，它可能会关闭一个流。如果发生这种情况，处理程序可能会在流关闭后尝试写入帧（因为尚未通知处理程序关闭）。在本例中，我们只需
	// 忽略帧。当
	// 等待写入帧时，处理程序会注意到流已关闭。
	// 
	// 作为此规则的例外，我们允许在关闭后发送RST_流。
	// 这允许我们立即拒绝新流，而无需跟踪这些流的任何
	// 状态（排队的RST_流帧除外）。此
	// 在某些情况下可能会导致重复的RST_流，但客户端应该忽略这些。
	if wr.StreamID() != 0 {
		_, isReset := wr.write.(http2StreamError)
		if state, _ := sc.state(wr.StreamID()); state == http2stateClosed && !isReset {
			ignoreWrite = true
		}
	}

	// 如果我们已经发送了头，请不要发送100 continue响应。
	// 见戈朗。org/issue/14030。
	switch wr.write.(type) {
	case *http2writeResHeaders:
		wr.stream.wroteHeaders = true
	case http2write100ContinueHeadersFrame:
		if wr.stream.wroteHeaders {
			// 我们不需要通知wr。因为这个框架是
			// 从来没有用wr写过。完成了！=无
			if wr.done != nil {
				panic("wr.done != nil for write100ContinueHeadersFrame")
			}
			ignoreWrite = true
		}
	}

	if !ignoreWrite {
		if wr.isControl() {
			sc.queuedControlFrames++
			// 为了额外的安全，检测不应该发生的包裹，
			// 然后拔下插头。
			if sc.queuedControlFrames < 0 {
				sc.conn.Close()
			}
		}
		sc.writeSched.Push(wr)
	}
	sc.scheduleFrameWrite()
}

// startFrameWrite启动一个goroutine来写入wr（在一个单独的
// goroutine中，因为这可能会在网络上阻塞），并更新
// serve goroutine关于世界的状态，从wr中的信息更新。
func (sc *http2serverConn) startFrameWrite(wr http2FrameWriteRequest) {
	sc.serveG.check()
	if sc.writingFrame {
		panic("internal error: can only be writing one frame at a time")
	}

	st := wr.stream
	if st != nil {
		switch st.state {
		case http2stateHalfClosedLocal:
			switch wr.write.(type) {
			case http2StreamError, http2handlerPanicRST, http2writeWindowUpdate:
				// RFC 7540第5.1节允许在此状态下发送RST_流、优先级和窗口更新
				// 。（我们从不从服务器发送优先级，因此不会进行检查。）
			default:
				panic(fmt.Sprintf("internal error: attempt to send frame on a half-closed-local stream: %v", wr))
			}
		case http2stateClosed:
			panic(fmt.Sprintf("internal error: attempt to send frame on a closed stream: %v", wr))
		}
	}
	if wpp, ok := wr.write.(*http2writePushPromise); ok {
		var err error
		wpp.promisedID, err = wpp.allocatePromisedID()
		if err != nil {
			sc.writingFrameAsync = false
			wr.replyToWriter(err)
			return
		}
	}

	sc.writingFrame = true
	sc.needsFrameFlush = true
	if wr.write.staysWithinBuffer(sc.bw.Available()) {
		sc.writingFrameAsync = false
		err := wr.write.writeFrame(sc)
		sc.wroteFrame(http2frameWriteResult{wr: wr, err: err})
	} else {
		sc.writingFrameAsync = true
		go sc.writeFrameAsync(wr)
	}
}

// errHandlerPanicked是在从
// 请求读取时，给任何被阻止的调用方的错误。当主要的goroutine惊慌失措时。由于大多数处理程序都是在
// main ServeHTTP goroutine中读取的，因此很少出现这种情况。
var http2errHandlerPanicked = errors.New("http2: handler panicked")

// wroteFrame在serve goroutine上被调用，其结果是
// writeFrameAsync上发生的任何事情。
func (sc *http2serverConn) wroteFrame(res http2frameWriteResult) {
	sc.serveG.check()
	if !sc.writingFrame {
		panic("internal error: expected to be already writing a frame")
	}
	sc.writingFrame = false
	sc.writingFrameAsync = false

	wr := res.wr

	if http2writeEndsStream(wr.write) {
		st := wr.stream
		if st == nil {
			panic("internal error: expecting non-nil stream")
		}
		switch st.state {
		case http2stateOpen:
			// 这里我们将转到
			// 理论中的StateHalf ClosedLocal，但由于我们的处理程序已经完成，并且
			// net/http包没有提供机制
			// 在仍然
			// 读取数据的情况下关闭响应编写器（请参阅
			// 此文件顶部的可能操作），我们在这里进入封闭状态
			// 无论如何，在告诉同龄人我们是
			// 挂断了他们之后。在写入RST_流帧
			// 状态关闭。
			// 之后，我们将转换到
			st.state = http2stateHalfClosedLocal
			// 第8.1节：服务器可以在发送完整响应后，通过发送错误代码为NO_error的
			// 传输请求。
			// RST_流，请求客户端无误中止
			sc.resetStream(http2streamError(st.id, http2ErrCodeNo))
		case http2stateHalfClosedRemote:
			sc.closeStream(st, http2errHandlerComplete)
		}
	} else {
		switch v := wr.write.(type) {
		case http2StreamError:
			// 如果生成RST_流以拒绝错误输入，则st可能未知。
			if st, ok := sc.streams[v.StreamID]; ok {
				sc.closeStream(st, v)
			}
		case http2handlerPanicRST:
			sc.closeStream(wr.stream, http2errHandlerPanicked)
		}
	}

	// 回复（如果请求）以解除对ServeHTTP goroutine的阻止。
	wr.replyToWriter(res.err)

	sc.scheduleFrameWrite()
}

// scheduleFrameWrite让帧写入调度器发痒。
// 
// 如果已经在写入帧，则不会发生任何事情。当框架完成写入时，将再次调用
// 。
// 
// 如果一个帧没有被写入，我们需要发送一个，最好的帧
// 发送由writeSched选择。
// 
// 如果一个帧没有被写入，并且没有其他东西可以发送，我们
// 刷新写入缓冲区。
func (sc *http2serverConn) scheduleFrameWrite() {
	sc.serveG.check()
	if sc.writingFrame || sc.inFrameScheduleLoop {
		return
	}
	sc.inFrameScheduleLoop = true
	for !sc.writingFrameAsync {
		if sc.needToSendGoAway {
			sc.needToSendGoAway = false
			sc.startFrameWrite(http2FrameWriteRequest{
				write: &http2writeGoAway{
					maxStreamID: sc.maxClientStreamID,
					code:        sc.goAwayCode,
				},
			})
			continue
		}
		if sc.needToSendSettingsAck {
			sc.needToSendSettingsAck = false
			sc.startFrameWrite(http2FrameWriteRequest{write: http2writeSettingsAck{}})
			continue
		}
		if !sc.inGoAway || sc.goAwayCode == http2ErrCodeNo {
			if wr, ok := sc.writeSched.Pop(); ok {
				if wr.isControl() {
					sc.queuedControlFrames--
				}
				sc.startFrameWrite(wr)
				continue
			}
		}
		if sc.needsFrameFlush {
			sc.startFrameWrite(http2FrameWriteRequest{write: http2flushFrameWriter{}})
			sc.needsFrameFlush = false // 在startFrameWrite之后，因为它设置了这个真正的
			continue
		}
		break
	}
	sc.inFrameScheduleLoop = false
}

// startGracefulShutdown会优雅地关闭连接。此
// 发送带有错误代码no的GOAWAY，告诉客户我们正在优雅地关闭
// 系统。在所有当前
// 流完成之前，连接不会关闭。
// 
// 立即启动快速关机；它不会等到
// 连接已关闭。
func (sc *http2serverConn) startGracefulShutdown() {
	sc.serveG.checkNotOn() // 非
	sc.shutdownOnce.Do(func() { sc.sendServeMsg(http2gracefulShutdownMsg) })
}

// 在发送带有错误代码的GOAWAY（非正常关机）后，
// 连接将在goAwayTimeout后关闭。
// 
// 如果在发送GOAWAY后立即关闭连接，内核接收缓冲区中可能会有未发送的数据，这将导致内核
// 在close（）上发送TCP RST，而不是FIN。此RST将立即中止
// 连接，无论客户端是否已收到GOAWAY。
// 
// 理想情况下，我们应该延迟至少1个RTT+epsilon，以便客户有机会阅读GOAWAY并停止发送消息。测量RTT 
// 很难，所以我们大约用1秒。见戈朗。org/issue/18701。
// 
// 这是一个变量，因此在测试中它可以更短，所有请求都使用
// 环回接口，使得预期的RTT非常小。
// 
// TODO:可配置？
var http2goAwayTimeout = 1 * time.Second

func (sc *http2serverConn) startGracefulShutdownInternal() {
	sc.goAway(http2ErrCodeNo)
}

func (sc *http2serverConn) goAway(code http2ErrCode) {
	sc.serveG.check()
	if sc.inGoAway {
		return
	}
	sc.inGoAway = true
	sc.needToSendGoAway = true
	sc.goAwayCode = code
	sc.scheduleFrameWrite()
}

func (sc *http2serverConn) shutDownIn(d time.Duration) {
	sc.serveG.check()
	sc.shutdownTimer = time.AfterFunc(d, sc.onShutdownTimer)
}

func (sc *http2serverConn) resetStream(se http2StreamError) {
	sc.serveG.check()
	sc.writeFrame(http2FrameWriteRequest{write: se})
	if st, ok := sc.streams[se.StreamID]; ok {
		st.resetQueued = true
	}
}

// processFrameFromReader处理从
// frame reading goroutine从readFrameCh读取的服务循环。
// processFrameFromReader返回连接是否应保持打开。
func (sc *http2serverConn) processFrameFromReader(res http2readFrameResult) bool {
	sc.serveG.check()
	err := res.err
	if err != nil {
		if err == http2ErrFrameTooLarge {
			sc.goAway(http2ErrCodeFrameSize)
			return true // goAway将关闭循环
		}
		clientGone := err == io.EOF || err == io.ErrUnexpectedEOF || http2isClosedConnError(err)
		if clientGone {
			// TODO:如果
			// 对等方执行半关闭
			// （例如CloseWrite），我们是否也会进入这种状态，因为他们完成了
			// 发送帧，但他们仍然需要
			// 我们的开放回复？侦查
			// TODO:将CloseWrite添加到crypto/tls。Conn first 
			// 那么我们有办法测试这个吗？我想
			// 仅仅为了测试，我们可以使用非TLS模式。
			return false
		}
	} else {
		f := res.f
		if http2VerboseLogs {
			sc.vlogf("http2: server read frame %v", http2summarizeFrame(f))
		}
		err = sc.processFrame(f)
		if err == nil {
			return true
		}
	}

	switch ev := err.(type) {
	case http2StreamError:
		sc.resetStream(ev)
		return true
	case http2goAwayFlowError:
		sc.goAway(http2ErrCodeFlowControl)
		return true
	case http2ConnectionError:
		sc.logf("http2: server connection error from %v: %v", sc.conn.RemoteAddr(), ev)
		sc.goAway(http2ErrCode(ev))
		return true // goAway将处理关闭
	default:
		if res.err != nil {
			sc.vlogf("http2: server closing client connection; error reading frame from client %s: %v", sc.conn.RemoteAddr(), err)
		} else {
			sc.logf("http2: server closing client connection: %v", err)
		}
		return false
	}
}

func (sc *http2serverConn) processFrame(f http2Frame) error {
	sc.serveG.check()

	// 接收到的第一帧必须是设置。
	if !sc.sawFirstSettings {
		if _, ok := f.(*http2SettingsFrame); !ok {
			return sc.countError("first_settings", http2ConnectionError(http2ErrCodeProtocol))
		}
		sc.sawFirstSettings = true
	}

	switch f := f.(type) {
	case *http2SettingsFrame:
		return sc.processSettings(f)
	case *http2MetaHeadersFrame:
		return sc.processHeaders(f)
	case *http2WindowUpdateFrame:
		return sc.processWindowUpdate(f)
	case *http2PingFrame:
		return sc.processPing(f)
	case *http2DataFrame:
		return sc.processData(f)
	case *http2RSTStreamFrame:
		return sc.processResetStream(f)
	case *http2PriorityFrame:
		return sc.processPriority(f)
	case *http2GoAwayFrame:
		return sc.processGoAway(f)
	case *http2PushPromiseFrame:
		// 客户端无法推送。因此，服务器必须将收到PUSH_PROMISE 
		// 帧视为协议_错误类型的连接错误（第5.4.1节）。
		return sc.countError("push_promise", http2ConnectionError(http2ErrCodeProtocol))
	default:
		sc.vlogf("http2: server ignoring frame: %v", f.Header())
		return nil
	}
}

func (sc *http2serverConn) processPing(f *http2PingFrame) error {
	sc.serveG.check()
	if f.IsAck() {
		// 6.7 PING：“端点不得响应包含此标志的PING帧
		// 。”
		return nil
	}
	if f.StreamID != 0 {
		// “PING帧不与任何单个
		// 流相关联。如果使用流
		// 标识符字段值而不是0x0接收PING帧，则接收方必须
		// 以
		// 协议错误类型的连接错误（第5.4.1节）响应。”
		return sc.countError("ping_on_stream", http2ConnectionError(http2ErrCodeProtocol))
	}
	if sc.inGoAway && sc.goAwayCode != http2ErrCodeNo {
		return nil
	}
	sc.writeFrame(http2FrameWriteRequest{write: http2writePingAck{f}})
	return nil
}

func (sc *http2serverConn) processWindowUpdate(f *http2WindowUpdateFrame) error {
	sc.serveG.check()
	switch {
	case f.StreamID != 0: // 流级流控制
		state, st := sc.state(f.StreamID)
		if state == http2stateIdle {
			// 第5.1节：“在这种状态下，接收除头
			// 或流优先级以外的任何帧必须被
			// 视为
			// 类型协议错误的连接错误（第5.4.1节）。”
			return sc.countError("stream_idle", http2ConnectionError(http2ErrCodeProtocol))
		}
		if st == nil {
			// “窗口更新可以由发送带有结束流标志的
			// 帧的对等方发送。这意味着
			// 接收器可以在“半
			// 关闭（远程）”或“关闭”流上接收窗口更新帧。接收器必须
			// 不要将其视为错误，请参阅第5.1节。”
			return nil
		}
		if !st.flow.add(int32(f.Increment)) {
			return sc.countError("bad_flow", http2streamError(f.StreamID, http2ErrCodeFlowControl))
		}
	default: // 连接级别流控制
		if !sc.flow.add(int32(f.Increment)) {
			return http2goAwayFlowError{}
		}
	}
	sc.scheduleFrameWrite()
	return nil
}

func (sc *http2serverConn) processResetStream(f *http2RSTStreamFrame) error {
	sc.serveG.check()

	state, st := sc.state(f.StreamID)
	if state == http2stateIdle {
		// 6.4“RST_流帧不得为处于“空闲”状态的
		// 流发送。如果接收到识别空闲流的RST_流帧
		// ，则
		// 接收方必须将其视为连接错误
		// （第5.4.1节）协议类型错误。
		return sc.countError("reset_idle_stream", http2ConnectionError(http2ErrCodeProtocol))
	}
	if st != nil {
		st.cancelCtx()
		sc.closeStream(st, http2streamError(f.StreamID, f.ErrCode))
	}
	return nil
}

func (sc *http2serverConn) closeStream(st *http2stream, err error) {
	sc.serveG.check()
	if st.state == http2stateIdle || st.state == http2stateClosed {
		panic(fmt.Sprintf("invariant; can't close stream in state %v", st.state))
	}
	st.state = http2stateClosed
	if st.writeDeadline != nil {
		st.writeDeadline.Stop()
	}
	if st.isPushed() {
		sc.curPushedStreams--
	} else {
		sc.curClientStreams--
	}
	delete(sc.streams, st.id)
	if len(sc.streams) == 0 {
		sc.setConnState(StateIdle)
		if sc.srv.IdleTimeout != 0 {
			sc.idleTimer.Reset(sc.srv.IdleTimeout)
		}
		if http2h1ServerKeepAlivesDisabled(sc.hs) {
			sc.startGracefulShutdownInternal()
		}
	}
	if p := st.body; p != nil {
		// 返回任何缓冲的未读字节值的conn级别流控制。
		// 见戈朗。org/issue/16481 
		sc.sendWindowUpdate(nil, p.Len())

		p.CloseWithError(err)
	}
	st.cw.Close() // 向处理程序的CloseNotifier发送信号，取消阻止写入等
	sc.writeSched.CloseStream(st.id)
}

func (sc *http2serverConn) processSettings(f *http2SettingsFrame) error {
	sc.serveG.check()
	if f.IsAck() {
		sc.unackedSettings--
		if sc.unackedSettings < 0 {
			// 为什么我们从未发送对等确认设置？
			// 规范中没有提到这种情况，但是
			// 无论如何，请挂断它们。
			return sc.countError("ack_mystery", http2ConnectionError(http2ErrCodeProtocol))
		}
		return nil
	}
	if f.NumSettings() > 100 || f.HasDuplicates() {
		// 这实际上不在规范中，但请挂断
		// 可疑的大设置帧或带有
		// 重复条目的帧。
		return sc.countError("settings_big_or_dups", http2ConnectionError(http2ErrCodeProtocol))
	}
	if err := f.ForeachSetting(sc.processSetting); err != nil {
		return err
	}
	// TODO:根据RFC 7540第6.5.3节判断，每个设置帧都应该单独确认
	// 即使在确认之前收到多个设置帧。
	sc.needToSendSettingsAck = true
	sc.scheduleFrameWrite()
	return nil
}

func (sc *http2serverConn) processSetting(s http2Setting) error {
	sc.serveG.check()
	if err := s.Valid(); err != nil {
		return err
	}
	if http2VerboseLogs {
		sc.vlogf("http2: server processing setting %v", s)
	}
	switch s.ID {
	case http2SettingHeaderTableSize:
		sc.headerTableSize = s.Val
		sc.hpackEncoder.SetMaxDynamicTableSize(s.Val)
	case http2SettingEnablePush:
		sc.pushEnabled = s.Val != 0
	case http2SettingMaxConcurrentStreams:
		sc.clientMaxStreams = s.Val
	case http2SettingInitialWindowSize:
		return sc.processSettingInitialWindowSize(s.Val)
	case http2SettingMaxFrameSize:
		sc.maxFrameSize = int32(s.Val) // 最大有效的s.Val是<2^31 
	case http2SettingMaxHeaderListSize:
		sc.peerMaxHeaderListSize = s.Val
	default:
		// 未知设置：“接收设置
		// 带有任何未知或不受支持标识符的帧的端点必须
		// 忽略该设置。”
		if http2VerboseLogs {
			sc.vlogf("http2: server ignoring unknown setting %v", s)
		}
	}
	return nil
}

func (sc *http2serverConn) processSettingInitialWindowSize(val uint32) error {
	sc.serveG.check()
	// 注意：val已被
	// processSetting的有效调用验证为在范围内。

	// “设置框可以更改所有当前流的初始流控制窗口
	// 大小。当
	// 设置初始窗口大小更改时，接收方必须
	// 调整其
	// 维护的所有流控制窗口的大小，即新值和
	// 旧v之间的差值价值。“
	old := sc.initialStreamSendWindowSize
	sc.initialStreamSendWindowSize = int32(val)
	growth := int32(val) - old // 可能为负
	for _, st := range sc.streams {
		if !st.flow.add(growth) {
			// 6.9.2初始流量控制窗口大小
			// ”端点必须处理对
			// 的更改，该设置会导致任何流量
			// 控制窗口超过最大大小，因为
			// 类型
			// 的连接错误（第5.4.1节）流量控制错误。“
			return sc.countError("setting_win_size", http2ConnectionError(http2ErrCodeFlowControl))
		}
	}
	return nil
}

func (sc *http2serverConn) processData(f *http2DataFrame) error {
	sc.serveG.check()
	id := f.Header().StreamID
	if sc.inGoAway && (sc.goAwayCode != http2ErrCodeNo || id > sc.maxClientStreamID) {
		// 如果GOAWAY是由于
		// 错误导致的，则放弃所有数据帧，或：
		// 
		// 第6.8节：发送GOAWAY帧后，发送方
		// 可以放弃由
		// 接收方发起的流的帧，其标识符高于识别的
		// 最后一个流。
		return nil
	}

	data := f.Data()
	state, st := sc.state(id)
	if id == 0 || state == http2stateIdle {
		// 第6.1节：“数据帧必须与
		// 流相关联。如果收到的数据帧的流
		// 标识符字段为0x0，则接收方必须以
		// 协议错误类型的连接错误（第5.4.1节）响应
		// 
		// 第5.1节：“在这种状态下，接收除头
		// 或流上的优先级以外的任何帧必须被
		// 视为
		// 的连接错误（第5.4.1节）。”
		return sc.countError("data_on_idle", http2ConnectionError(http2ErrCodeProtocol))
	}

	// “如果接收到的数据帧的流未处于“打开”
	// 或“半关闭（本地）”状态，则接收方必须以流_closed类型的流错误（第5.4.2节）响应
	// 。”
	if st == nil || state != http2stateOpen || st.gotTrailerHeader || st.resetQueued {
		// 这包括在stateHalfClosedLocal中发送RST_流，如果该流是
		// 的话（目前这意味着
		// http.Handler返回，因此它已经完成读取和
		// 完成写入）。尝试阻止客户端发送
		// 更多数据。

		// 但仍然执行其连接级别的流控制，
		// 并返回任何流控制字节，因为我们不会使用它们。
		if sc.inflow.available() < int32(f.Length) {
			return sc.countError("data_flow", http2streamError(id, http2ErrCodeFlowControl))
		}
		// 从流入中扣除流量控制，因为我们是
		// 将立即将其添加回
		// sendWindowUpdate，它还计划发送
		// 帧。
		sc.inflow.take(int32(f.Length))
		sc.sendWindowUpdate(nil, int(f.Length)) // 连接级别

		if st != nil && st.resetQueued {
			// 在飞行中已出现流错误。别再发了。
			return nil
		}
		return sc.countError("closed", http2streamError(id, http2ErrCodeStreamClosed))
	}
	if st.body == nil {
		panic("internal error: should have a body in this state")
	}

	// 发件人发送的邮件比他们声明的多？
	if st.declBodyBytes != -1 && st.bodyBytes+int64(len(data)) > st.declBodyBytes {
		st.body.CloseWithError(fmt.Errorf("sender tried to send more than declared Content-Length of %d bytes", st.declBodyBytes))
		// RFC 7540，第8.1.2.6节：如果内容长度头字段的
		// 值不等于构成正文的
		// 数据帧有效负载长度之和，则请求或响应的格式也不正确。
		return sc.countError("send_too_much", http2streamError(id, http2ErrCodeProtocol))
	}
	if f.Length > 0 {
		// 检查客户端是否有流量控制配额。
		if st.inflow.available() < int32(f.Length) {
			return sc.countError("flow_on_data_length", http2streamError(id, http2ErrCodeFlowControl))
		}
		st.inflow.take(int32(f.Length))

		if len(data) > 0 {
			wrote, err := st.body.Write(data)
			if err != nil {
				sc.sendWindowUpdate(nil, int(f.Length)-wrote)
				return sc.countError("body_write_err", http2streamError(id, http2ErrCodeStreamClosed))
			}
			if wrote != len(data) {
				panic("internal error: bad Writer")
			}
			st.bodyBytes += int64(len(data))
		}

		// 现在返回任何填充的流控制，因为我们不会在以后的正文阅读中退款。
		if pad := int32(f.Length) - int32(len(data)); pad > 0 {
			sc.sendWindowUpdate32(nil, pad)
			sc.sendWindowUpdate32(st, pad)
		}
	}
	if f.StreamEnded() {
		st.endStream()
	}
	return nil
}

func (sc *http2serverConn) processGoAway(f *http2GoAwayFrame) error {
	sc.serveG.check()
	if f.ErrCode != http2ErrCodeNo {
		sc.logf("http2: received GOAWAY %+v, starting graceful shutdown", f)
	} else {
		sc.vlogf("http2: received GOAWAY %+v, starting graceful shutdown", f)
	}
	sc.startGracefulShutdownInternal()
	// http:
	// 我们不应该创建任何新的流，这意味着我们应该禁用推送。
	sc.pushEnabled = false
	return nil
}

// isPushed报告流是否由服务器启动。
func (st *http2stream) isPushed() bool {
	return st.id%2 == 0
}

// endStream关闭一个请求。身体的管子。当数据
// 帧表示请求主体已结束（或结束后）时，会调用该函数。
func (st *http2stream) endStream() {
	sc := st.sc
	sc.serveG.check()

	if st.declBodyBytes != -1 && st.declBodyBytes != st.bodyBytes {
		st.body.CloseWithError(fmt.Errorf("request declared a Content-Length of %d but only wrote %d bytes",
			st.declBodyBytes, st.bodyBytes))
	} else {
		st.body.closeWithErrorAndCode(io.EOF, st.copyTrailersToHandlerRequest)
		st.body.CloseWithError(io.EOF)
	}
	st.state = http2stateHalfClosedRemote
}

// copyTrailersToHandlerRequest在
// 其请求中的处理程序的goroutine中运行。身体在它得到io之前阅读。EOF。
func (st *http2stream) copyTrailersToHandlerRequest() {
	for k, vv := range st.trailer {
		if _, ok := st.reqTrailer[k]; ok {
			// 只在预先声明的基础上复制。
			st.reqTrailer[k] = vv
		}
	}
}

// 当流的WriteTimeout被触发时，onWriteTimeout在其自己的goroutine（from time.AfterFunc）上运行。
func (st *http2stream) onWriteTimeout() {
	st.sc.writeFrameFromHandler(http2FrameWriteRequest{write: http2streamError(st.id, http2ErrCodeInternal)})
}

func (sc *http2serverConn) processHeaders(f *http2MetaHeadersFrame) error {
	sc.serveG.check()
	id := f.StreamID
	if sc.inGoAway {
		// 忽略。
		return nil
	}
	// http:
	// 客户端启动的流必须使用奇数编号的流
	// 标识符。[...] 接收到意外
	// 流标识符的端点必须以PROTOCOL_error类型的连接错误
	// （第5.4.1节）进行响应。
	if id%2 != 1 {
		return sc.countError("headers_even", http2ConnectionError(http2ErrCodeProtocol))
	}
	// 头帧可用于创建新流，或
	// 发送一个打开流的预告片。如果我们已经有一个流
	// 打开，让它处理它自己的头帧（如果它有效的话，在这个
	// 点的拖车）。
	if st := sc.streams[f.StreamID]; st != nil {
		if st.resetQueued {
			// 我们正在发送RST_流来关闭流，所以不要麻烦
			// 处理这个帧。
			return nil
		}
		// RFC 7540，第5.1节：对于处于
		// 窗口更新、优先级或RST_流以外的其他帧，则它必须以
		// 此状态的流，如果端点接收到除
		// 类型STREAM_CLOSED的流错误（第5.4.2节）响应。
		if st.state == http2stateHalfClosedRemote {
			return sc.countError("headers_half_closed", http2streamError(id, http2ErrCodeStreamClosed))
		}
		return st.processTrailerHeaders(f)
	}

	// /[…]新建立的流的标识符必须是
	// 数值大于发起
	// 端点已打开或保留的所有流。[...]  
	// 接收到意外流标识符的终结点必须以
	// 类型为PROTOCOL_error的连接错误（第5.4.1节）进行响应。
	if id <= sc.maxClientStreamID {
		return sc.countError("stream_went_down", http2ConnectionError(http2ErrCodeProtocol))
	}
	sc.maxClientStreamID = id

	if sc.idleTimer != nil {
		sc.idleTimer.Stop()
	}

	// http:
	// […]端点不得超过其对等方设置的限制。
	// 接收导致超出其
	// 播发的并发流限制的头帧的终结点必须将
	// 视为协议_error
	// 或拒绝_stream类型的流错误（第5.4.2节）。
	if sc.curClientStreams+1 > sc.advMaxStreams {
		if sc.unackedSettings == 0 {
			// 他们应该更清楚。
			return sc.countError("over_max_streams", http2streamError(id, http2ErrCodeProtocol))
		}
		// 假设这是一场网络竞赛，他们只是没有收到我们上次的设置更新。但实际上，这还不可能发生，因为我们还没有提供用户在运行时调整服务器参数的方法。
		return sc.countError("over_max_streams_race", http2streamError(id, http2ErrCodeRefusedStream))
	}

	initialState := http2stateOpen
	if f.StreamEnded() {
		initialState = http2stateHalfClosedRemote
	}
	st := sc.newStream(id, 0, initialState)

	if f.HasPriority() {
		if err := sc.checkPriority(f.StreamID, f.Priority); err != nil {
			return err
		}
		sc.writeSched.AdjustStream(st.id, f.Priority)
	}

	rw, req, err := sc.newWriterAndRequest(st, f)
	if err != nil {
		return err
	}
	st.reqTrailer = req.Trailer
	if st.reqTrailer != nil {
		st.trailer = make(Header)
	}
	st.body = req.Body.(*http2requestBody).pipe // 可能为零
	st.declBodyBytes = req.ContentLength

	handler := sc.handler.ServeHTTP
	if f.Truncated {
		// 他们的标题列表太长。发送431错误。
		handler = http2handleHeaderListTooLong
	} else if err := http2checkValidHTTP2RequestHeaders(req.Header); err != nil {
		handler = http2new400Handler(err)
	}

	// net/http包设置从
	// http读取的截止日期。服务器在TLS握手过程中读取超时，但随后
	// 将连接传递给我们，截止日期已设置。读取请求头后在此处解除它的防护，
	// 类似于http1服务器的工作方式。这里是
	// 技术上更像http1服务器的ReadHeaderTimeout 
	// （在Go 1.8中）。无论如何，这是一个更明智的选择。
	if sc.hs.ReadTimeout != 0 {
		sc.conn.SetReadDeadline(time.Time{})
	}

	go sc.runHandler(rw, req, handler)
	return nil
}

func (st *http2stream) processTrailerHeaders(f *http2MetaHeadersFrame) error {
	sc := st.sc
	sc.serveG.check()
	if st.gotTrailerHeader {
		return sc.countError("dup_trailers", http2ConnectionError(http2ErrCodeProtocol))
	}
	st.gotTrailerHeader = true
	if !f.StreamEnded() {
		return sc.countError("trailers_not_ended", http2streamError(st.id, http2ErrCodeProtocol))
	}

	if len(f.PseudoFields()) > 0 {
		return sc.countError("trailers_pseudo", http2streamError(st.id, http2ErrCodeProtocol))
	}
	if st.trailer != nil {
		for _, hf := range f.RegularFields() {
			key := sc.canonicalHeader(hf.Name)
			if !httpguts.ValidTrailerHeader(key) {
				// 待办事项：以某种方式向同行发送更多详细信息。但是http2有
				// 无法在流级别发送调试数据。与
				// HTTP folk讨论。
				return sc.countError("trailers_bogus", http2streamError(st.id, http2ErrCodeProtocol))
			}
			st.trailer[key] = append(st.trailer[key], hf.Value)
		}
	}
	st.endStream()
	return nil
}

func (sc *http2serverConn) checkPriority(streamID uint32, p http2PriorityParam) error {
	if streamID == p.StreamDep {
		// 第5.3.1节：“流不能依赖于自身。端点必须将
		// 视为协议_错误类型的流错误（第5.4.2节）。”
		// 第5.3.3节说，流可以依赖于它的一个依赖项，所以只有自依赖项是被禁止的。
		return sc.countError("priority", http2streamError(streamID, http2ErrCodeProtocol))
	}
	return nil
}

func (sc *http2serverConn) processPriority(f *http2PriorityFrame) error {
	if sc.inGoAway {
		return nil
	}
	if err := sc.checkPriority(f.StreamID, f.http2PriorityParam); err != nil {
		return err
	}
	sc.writeSched.AdjustStream(f.StreamID, f.http2PriorityParam)
	return nil
}

func (sc *http2serverConn) newStream(id, pusherID uint32, state http2streamState) *http2stream {
	sc.serveG.check()
	if id == 0 {
		panic("internal error: cannot create stream with id 0")
	}

	ctx, cancelCtx := context.WithCancel(sc.baseCtx)
	st := &http2stream{
		sc:        sc,
		id:        id,
		state:     state,
		ctx:       ctx,
		cancelCtx: cancelCtx,
	}
	st.cw.Init()
	st.flow.conn = &sc.flow // 链接到conn级计数器
	st.flow.add(sc.initialStreamSendWindowSize)
	st.inflow.conn = &sc.inflow // 链接到conn级计数器
	st.inflow.add(sc.srv.initialStreamRecvWindowSize())
	if sc.hs.WriteTimeout != 0 {
		st.writeDeadline = time.AfterFunc(sc.hs.WriteTimeout, st.onWriteTimeout)
	}

	sc.streams[id] = st
	sc.writeSched.OpenStream(st.id, http2OpenStreamOptions{PusherID: pusherID})
	if st.isPushed() {
		sc.curPushedStreams++
	} else {
		sc.curClientStreams++
	}
	if sc.curOpenStreams() == 1 {
		sc.setConnState(StateActive)
	}

	return st
}

func (sc *http2serverConn) newWriterAndRequest(st *http2stream, f *http2MetaHeadersFrame) (*http2responseWriter, *Request, error) {
	sc.serveG.check()

	rp := http2requestParam{
		method:    f.PseudoValue("method"),
		scheme:    f.PseudoValue("scheme"),
		authority: f.PseudoValue("authority"),
		path:      f.PseudoValue("path"),
	}

	isConnect := rp.method == "CONNECT"
	if isConnect {
		if rp.path != "" || rp.scheme != "" || rp.authority == "" {
			return nil, nil, sc.countError("bad_connect", http2streamError(f.StreamID, http2ErrCodeProtocol))
		}
	} else if rp.method == "" || rp.path == "" || (rp.scheme != "https" && rp.scheme != "http") {
		// 请参阅8.1.2.6格式错误的请求和响应：
		// 
		// 检测到的格式错误的请求或响应
		// 必须视为流错误（第5.4.2节）
		// 类型协议错误。“
		// 
		// 8.1.2.3请求伪头字段
		// ”所有HTTP/2请求必须只包含一个有效的
		// ，和：path 
		// 伪头字段“
		return nil, nil, sc.countError("bad_path_method", http2streamError(f.StreamID, http2ErrCodeProtocol))
	}

	bodyOpen := !f.StreamEnded()
	if rp.method == "HEAD" && bodyOpen {
		// 头请求不能有正文
		return nil, nil, sc.countError("head_body", http2streamError(f.StreamID, http2ErrCodeProtocol))
	}

	rp.header = make(Header)
	for _, hf := range f.RegularFields() {
		rp.header.Add(sc.canonicalHeader(hf.Name), hf.Value)
	}
	if rp.authority == "" {
		rp.authority = rp.header.Get("Host")
	}

	rw, req, err := sc.newWriterAndRequestNoBody(st, rp)
	if err != nil {
		return nil, nil, err
	}
	if bodyOpen {
		if vv, ok := rp.header["Content-Length"]; ok {
			if cl, err := strconv.ParseUint(vv[0], 10, 63); err == nil {
				req.ContentLength = int64(cl)
			} else {
				req.ContentLength = 0
			}
		} else {
			req.ContentLength = -1
		}
		req.Body.(*http2requestBody).pipe = &http2pipe{
			b: &http2dataBuffer{expected: req.ContentLength},
		}
	}
	return rw, req, nil
}

type http2requestParam struct {
	method                  string
	scheme, authority, path string
	header                  Header
}

func (sc *http2serverConn) newWriterAndRequestNoBody(st *http2stream, rp http2requestParam) (*http2responseWriter, *Request, error) {
	sc.serveG.check()

	var tlsState *tls.ConnectionState // 如果没有方案https 
	if rp.scheme == "https" {
		tlsState = sc.tlsState
	}

	needsContinue := rp.header.Get("Expect") == "100-continue"
	if needsContinue {
		rp.header.Del("Expect")
	}
	// 将Cookie头合并为一个”；“-带分隔符的值。
	if cookies := rp.header["Cookie"]; len(cookies) > 1 {
		rp.header.Set("Cookie", strings.Join(cookies, "; "))
	}

	// 安装程序
	var trailer Header
	for _, v := range rp.header["Trailer"] {
		for _, key := range strings.Split(v, ",") {
			key = CanonicalHeaderKey(textproto.TrimString(key))
			switch key {
			case "Transfer-Encoding", "Trailer", "Content-Length":
				// 伪。（http1规则副本）
				// 忽略。
			default:
				if trailer == nil {
					trailer = make(Header)
				}
				trailer[key] = nil
			}
		}
	}
	delete(rp.header, "Trailer")

	var url_ *url.URL
	var requestURI string
	if rp.method == "CONNECT" {
		url_ = &url.URL{Host: rp.authority}
		requestURI = rp.authority // 模仿HTTP/1服务器行为
	} else {
		var err error
		url_, err = url.ParseRequestURI(rp.path)
		if err != nil {
			return nil, nil, sc.countError("bad_path", http2streamError(st.id, http2ErrCodeProtocol))
		}
		requestURI = rp.path
	}

	body := &http2requestBody{
		conn:          sc,
		stream:        st,
		needsContinue: needsContinue,
	}
	req := &Request{
		Method:     rp.method,
		URL:        url_,
		RemoteAddr: sc.remoteAddrStr,
		Header:     rp.header,
		RequestURI: requestURI,
		Proto:      "HTTP/2.0",
		ProtoMajor: 2,
		ProtoMinor: 0,
		TLS:        tlsState,
		Host:       rp.authority,
		Body:       body,
		Trailer:    trailer,
	}
	req = req.WithContext(st.ctx)

	rws := http2responseWriterStatePool.Get().(*http2responseWriterState)
	bwSave := rws.bw
	*rws = http2responseWriterState{} // 将所有字段归零
	rws.conn = sc
	rws.bw = bwSave
	rws.bw.Reset(http2chunkWriter{rws})
	rws.stream = st
	rws.req = req
	rws.body = body

	rw := &http2responseWriter{rws: rws}
	return rw, req, nil
}

// 在自己的goroutine上运行。
func (sc *http2serverConn) runHandler(rw *http2responseWriter, req *Request, handler func(ResponseWriter, *Request)) {
	didPanic := true
	defer func() {
		rw.rws.stream.cancelCtx()
		if didPanic {
			e := recover()
			sc.writeFrameFromHandler(http2FrameWriteRequest{
				write:  http2handlerPanicRST{rw.rws.stream.id},
				stream: rw.rws.stream,
			})
			// 与net/http:
			if e != nil && e != ErrAbortHandler {
				const size = 64 << 10
				buf := make([]byte, size)
				buf = buf[:runtime.Stack(buf, false)]
				sc.logf("http2: panic serving %v: %v\n%s", sc.conn.RemoteAddr(), e, buf)
			}
			return
		}
		rw.handlerDone()
	}()
	handler(rw, req)
	didPanic = false
}

func http2handleHeaderListTooLong(w ResponseWriter, r *Request) {
	// 10.5.1头块大小限制：
	// 。。“接收到比它更大的头块的服务器
	// 愿意处理的服务器可以发送HTTP 431（请求头字段太多
	// 大）状态码”
	const statusRequestHeaderFieldsTooLarge = 431 // 仅在Go 1.6+
	w.WriteHeader(statusRequestHeaderFieldsTooLarge)
	io.WriteString(w, "<h1>HTTP Error 431</h1><p>Request Header Field(s) Too Large</p>")
}

// 中从处理程序goroutines调用。
// h可能为零。
func (sc *http2serverConn) writeHeaders(st *http2stream, headerData *http2writeResHeaders) error {
	sc.serveG.checkNotOn() // 不在
	var errc chan error
	if headerData.h != nil {
		// 如果有一个头映射（我们没有），那么我们必须在
		// 上阻塞，等待写入这个帧，所以http。Flush mid handler 
		// 在处理程序稍后可能对其进行变异之前，写出正确的键值。
		errc = http2errChanPool.Get().(chan error)
	}
	if err := sc.writeFrameFromHandler(http2FrameWriteRequest{
		write:  headerData,
		stream: st,
		done:   errc,
	}); err != nil {
		return err
	}
	if errc != nil {
		select {
		case err := <-errc:
			http2errChanPool.Put(errc)
			return err
		case <-sc.doneServing:
			return http2errClientDisconnected
		case <-st.cw:
			return http2errStreamClosed
		}
	}
	return nil
}

// 从处理程序goroutines调用。
func (sc *http2serverConn) write100ContinueHeaders(st *http2stream) {
	sc.writeFrameFromHandler(http2FrameWriteRequest{
		write:  http2write100ContinueHeadersFrame{st.id},
		stream: st,
	})
}

// bodyReadMsg告诉服务器循环http。处理程序从给定流上的客户端读取n 
// 字节的数据。
type http2bodyReadMsg struct {
	st *http2stream
	n  int
}

// 从处理程序goroutines调用。
// 注意，给定流ID的处理程序读取其主体的n字节，并计划发送流控制令牌。
func (sc *http2serverConn) noteBodyReadFromHandler(st *http2stream, n int, err error) {
	sc.serveG.checkNotOn() // 不在
	if n > 0 {
		select {
		case sc.bodyReadCh <- http2bodyReadMsg{st, n}:
		case <-sc.doneServing:
		}
	}
}

func (sc *http2serverConn) noteBodyRead(st *http2stream, n int) {
	sc.serveG.check()
	sc.sendWindowUpdate(nil, n) // 连接级别
	if st.state != http2stateHalfClosedRemote && st.state != http2stateClosed {
		// 如果流关闭，则不发送此窗口更新
		// 远程。
		sc.sendWindowUpdate(st, n)
	}
}

// 对于conn级别
func (sc *http2serverConn) sendWindowUpdate(st *http2stream, n int) {
	sc.serveG.check()
	// “流量控制
	// 窗口增量的法定范围为1到2^31-1（2147483647）个八位字节。”
	// 64位机器上的Go-Read调用理论上可以读取
	// /比这更大的读取。不太可能，但我们现在在这里处理
	// 而不是在其他地方。
	const maxUint31 = 1<<31 - 1
	for n >= maxUint31 {
		sc.sendWindowUpdate32(st, maxUint31)
		n -= maxUint31
	}
	sc.sendWindowUpdate32(st, int32(n))
}

// st对于conn级别
func (sc *http2serverConn) sendWindowUpdate32(st *http2stream, n int32) {
	sc.serveG.check()
	if n == 0 {
		return
	}
	if n < 0 {
		panic("negative update")
	}
	var streamID uint32
	if st != nil {
		streamID = st.id
	}
	sc.writeFrame(http2FrameWriteRequest{
		write:  http2writeWindowUpdate{streamID: streamID, n: uint32(n)},
		stream: st,
	})
	var ok bool
	if st == nil {
		ok = sc.inflow.add(n)
	} else {
		ok = st.inflow.add(n)
	}
	if !ok {
		panic("internal error; sent too many window updates without decrements?")
	}
}

// requestBody是处理程序的请求。体型。
// 可以同时调用Read和Close。
type http2requestBody struct {
	_             http2incomparable
	stream        *http2stream
	conn          *http2serverConn
	closed        bool       // 仅供近距离使用
	sawEOF        bool       // 仅供只读
	pipe          *http2pipe // 如果我们有HTTP实体消息体，则非零
	needsContinue bool       // 需要发送100个连续
}

func (b *http2requestBody) Close() error {
	if b.pipe != nil && !b.closed {
		b.pipe.BreakWithError(http2errClosedBody)
	}
	b.closed = true
	return nil
}

func (b *http2requestBody) Read(p []byte) (n int, err error) {
	if b.needsContinue {
		b.needsContinue = false
		b.conn.write100ContinueHeaders(b.stream)
	}
	if b.pipe == nil || b.sawEOF {
		return 0, io.EOF
	}
	n, err = b.pipe.Read(p)
	if err == io.EOF {
		b.sawEOF = true
	}
	if b.conn == nil && http2inTests {
		return
	}
	b.conn.noteBodyReadFromHandler(b.stream, n, err)
	return
}

// 响应编写器是HTTP。ResponseWriter实现。它是
// 故意小（1个指针宽）以最小化垃圾。
// 内部的responseWriterState指针在
// 请求（在handlerDone中）的末尾归零，然后调用responseWriter 
// 简单地崩溃（调用方的错误），但更大的responseWriterState 
// 并且在多个请求之间重用缓冲区。
type http2responseWriter struct {
	rws *http2responseWriterState
}

// 可选http。实现了ResponseWriter接口。
var (
	_ CloseNotifier     = (*http2responseWriter)(nil)
	_ Flusher           = (*http2responseWriter)(nil)
	_ http2stringWriter = (*http2responseWriter)(nil)
)

type http2responseWriterState struct {
	// 在请求中不可变：
	stream *http2stream
	req    *Request
	body   *http2requestBody // 在请求结束时关闭，如果数据帧没有
	conn   *http2serverConn

	// TODO:根据服务器配置、来自对等方的帧大小更新等调整缓冲区写入大小
	bw *bufio.Writer // 写入chunkWriter{this*responseWriterState}

	// 由http修改。Handler goroutine:
	handlerHeader Header   // nil直到调用
	snapHeader    Header   // 在WriteHeader时间的handlerHeader快照
	trailers      []string // 在writeChunk中设置
	status        int      // 传递给WriteHeader的状态代码
	wroteHeader   bool     // WriteHeader调用（显式或隐式）。不一定发送给用户。
	sentHeader    bool     // 我们发送了头帧了吗？
	handlerDone   bool     // 处理程序已完成
	dirty         bool     // 写入失败；如果处理程序设置了一个内容长度头

	sentContentLen int64 // 非零，直到写入
	wroteBytes     int64

	closeNotifierMu sync.Mutex // guards closeNotifierCh 
	closeNotifierCh chan bool  // nil，则不要重复使用此responseWriterState 
}

type http2chunkWriter struct{ rws *http2responseWriterState }

func (cw http2chunkWriter) Write(p []byte) (n int, err error) { return cw.rws.writeChunk(p) }

func (rws *http2responseWriterState) hasTrailers() bool { return len(rws.trailers) > 0 }

func (rws *http2responseWriterState) hasNonemptyTrailers() bool {
	for _, trailer := range rws.trailers {
		if _, ok := rws.handlerHeader[trailer]; ok {
			return true
		}
	}
	return false
}

// declareTrailer。它注意到，在响应末尾的预告片中需要写入
// 响应头时为每个尾部头调用了第一次使用的
// 标题。
func (rws *http2responseWriterState) declareTrailer(k string) {
	k = CanonicalHeaderKey(k)
	if !httpguts.ValidTrailerHeader(k) {
		// RFC 7230第4.1.2节禁止。
		rws.conn.logf("ignoring invalid trailer %q", k)
		return
	}
	if !http2strSliceContains(rws.trailers, k) {
		rws.trailers = append(rws.trailers, k)
	}
}

// writeChunk从bufio写入块。作家但是因为
// bufio。Writer可能会绕过它的分块，有时p可能是
// 任意大。
// 
// writeChunk还负责（在第一个区块上）发送
// 头响应。
func (rws *http2responseWriterState) writeChunk(p []byte) (n int, err error) {
	if !rws.wroteHeader {
		rws.writeHeader(200)
	}

	isHeadResp := rws.req.Method == "HEAD"
	if !rws.sentHeader {
		rws.sentHeader = true
		var ctype, clen string
		if clen = rws.snapHeader.Get("Content-Length"); clen != "" {
			rws.snapHeader.Del("Content-Length")
			if cl, err := strconv.ParseUint(clen, 10, 63); err == nil {
				rws.sentContentLen = int64(cl)
			} else {
				clen = ""
			}
		}
		if clen == "" && rws.handlerDone && http2bodyAllowedForStatus(rws.status) && (len(p) > 0 || !isHeadResp) {
			clen = strconv.Itoa(len(p))
		}
		_, hasContentType := rws.snapHeader["Content-Type"]
		// 如果内容编码是非空的，我们不应该嗅探身体。见问题golang。org/issue/31753。
		ce := rws.snapHeader.Get("Content-Encoding")
		hasCE := len(ce) > 0
		if !hasCE && !hasContentType && http2bodyAllowedForStatus(rws.status) && len(p) > 0 {
			ctype = DetectContentType(p)
		}
		var date string
		if _, ok := rws.snapHeader["Date"]; !ok {
			// TODO（bradfitz）：在这里更快，比如net/http？测量
			date = time.Now().UTC().Format(TimeFormat)
		}

		for _, v := range rws.snapHeader["Trailer"] {
			http2foreachHeaderElement(v, rws.declareTrailer)
		}

		// “连接”头在HTTP/2（RFC 7540，8.1.2.2）中是不允许的，但是尊重“连接”==“关闭”意味着在空闲时发送一个GOAWAY并撕毁TCP连接，就像我们在HTTP/1中所做的那样。
		// TODO:除了
		// “连接”之外，在此处删除更多特定于连接的头字段。
		if _, ok := rws.snapHeader["Connection"]; ok {
			v := rws.snapHeader.Get("Connection")
			delete(rws.snapHeader, "Connection")
			if v == "close" {
				rws.conn.startGracefulShutdown()
			}
		}

		endStream := (rws.handlerDone && !rws.hasTrailers() && len(p) == 0) || isHeadResp
		err = rws.conn.writeHeaders(rws.stream, &http2writeResHeaders{
			streamID:      rws.stream.id,
			httpResCode:   rws.status,
			h:             rws.snapHeader,
			endStream:     endStream,
			contentType:   ctype,
			contentLength: clen,
			date:          date,
		})
		if err != nil {
			rws.dirty = true
			return 0, err
		}
		if endStream {
			return 0, nil
		}
	}
	if isHeadResp {
		return len(p), nil
	}
	if len(p) == 0 && !rws.handlerDone {
		return 0, nil
	}

	if rws.handlerDone {
		rws.promoteUndeclaredTrailers()
	}

	// 仅当服务器处理程序实际定义了预告片时才发送预告片。
	hasNonemptyTrailers := rws.hasNonemptyTrailers()
	endStream := rws.handlerDone && !hasNonemptyTrailers
	if len(p) > 0 || endStream {
		// 如果要结束流，只发送一个0字节的数据帧。
		if err := rws.conn.writeDataFromHandler(rws.stream, p, endStream); err != nil {
			rws.dirty = true
			return 0, err
		}
	}

	if rws.handlerDone && hasNonemptyTrailers {
		err = rws.conn.writeHeaders(rws.stream, &http2writeResHeaders{
			streamID:  rws.stream.id,
			h:         rws.handlerHeader,
			trailers:  rws.trailers,
			endStream: true,
		})
		if err != nil {
			rws.dirty = true
		}
		return len(p), err
	}
	return len(p), nil
}

// TrailerPrefix是ResponseWriter的神奇前缀。Header map key 
// 如果存在，则表明map条目实际上是针对
// 响应预告片的，而不是响应头。ServeHTTP调用完成后，前缀
// 被剥离，值被发送到预告片中。
// 
// 此机制仅适用于在写入标题之前未知的拖车
// 。如果拖车组是固定的
// 或在写入报头之前已知的，则首选正常的Go拖车机制
// 
// https:
// https:
const http2TrailerPrefix = "Trailer:"

// 促销员和申报的Railers允许http。在头已经刷新后设置
// 的处理程序。因为Go 
// ResponseWriter接口无法设置预告片（只有
// 标题），因为我们不想扩展ResponseWriter 
// 接口，因为没有人使用预告片，因为RFC 7230 
// 说你应该（但不是必须）预先声明
// 标题中的任何预告片，官方的ResponseWriter规则规定Go中的预告片必须预先声明，然后我们重复使用同一个ResponseWriter。Header（）
// map表示头和尾。在编写
// 预告片时，我们会选择声明为
// 预告片的头字段。这项工作进行了一段时间，直到我们发现了第一个主要的野生拖车用户：gRPC（仅在http2上使用）、gRPC库允许在中途设置拖车，而不需要预先删除它们。所以：改变计划。我们仍然允许使用旧的
// 方式，但我们也允许这种攻击：如果Header（）键以
// “Trailer:”开头，则该键的后缀为Trailer:。因为“：”是
// 无效的令牌字节，所以没有歧义。（它已经被
// 过滤掉）它有点黑客味，但并不可怕。
// 
// 此方法在处理程序完成后运行，并将任何头
// 字段升级为尾部。
func (rws *http2responseWriterState) promoteUndeclaredTrailers() {
	for k, vv := range rws.handlerHeader {
		if !strings.HasPrefix(k, http2TrailerPrefix) {
			continue
		}
		trailerKey := strings.TrimPrefix(k, http2TrailerPrefix)
		rws.declareTrailer(trailerKey)
		rws.handlerHeader[CanonicalHeaderKey(trailerKey)] = vv
	}

	if len(rws.trailers) > 1 {
		sorter := http2sorterPool.Get().(*http2sorter)
		sorter.SortStrings(rws.trailers)
		http2sorterPool.Put(sorter)
	}
}

func (w *http2responseWriter) Flush() {
	rws := w.rws
	if rws == nil {
		panic("Header called after Handler finished")
	}
	if rws.bw.Buffered() > 0 {
		if err := rws.bw.Flush(); err != nil {
			// 忽略错误。框架作者已经知道了。
			return
		}
	} else {
		// bufio。Writer不会给chunkWriter打电话。写入
		// （writeChunk为零字节，因此我们必须自己执行
		// /强制发送HTTP响应头和/或
		// /最终数据帧（带END_流）。
		rws.writeChunk(nil)
	}
}

func (w *http2responseWriter) CloseNotify() <-chan bool {
	rws := w.rws
	if rws == nil {
		panic("CloseNotify called after Handler finished")
	}
	rws.closeNotifierMu.Lock()
	ch := rws.closeNotifierCh
	if ch == nil {
		ch = make(chan bool, 1)
		rws.closeNotifierCh = ch
		cw := rws.stream.cw
		go func() {
			cw.Wait() // 等待关闭
			ch <- true
		}()
	}
	rws.closeNotifierMu.Unlock()
	return ch
}

func (w *http2responseWriter) Header() Header {
	rws := w.rws
	if rws == nil {
		panic("Header called after Handler finished")
	}
	if rws.handlerHeader == nil {
		rws.handlerHeader = make(Header)
	}
	return rws.handlerHeader
}

// checkWriteHeaderCode是net/http的checkWriteHeaderCode的副本。
func http2checkWriteHeaderCode(code int) {
	// 问题22880:需要有效的写入头状态代码。
	// 目前我们只强制要求它是三位数。
	// 未来我们可能会阻止超过599的内容（600及以上未定义
	// 在http:
	// 我们可能会阻止200以下（一旦我们有了更成熟的1x支持）。
	// 但现在是任意三位数字。
	// 
	// 我们过去经常在网上发送“HTTP/1.1 000 0”作为回应，但这里有
	// 在HTTP/2中，我们实际上无法发送同等的虚假信息，所以我们会一直惊慌失措，帮助人们尽早发现他们的漏洞
	// 。（即使我们愿意，也无法从WriteHeader返回错误。）
	if code < 100 || code > 999 {
		panic(fmt.Sprintf("invalid WriteHeader code %v", code))
	}
}

func (w *http2responseWriter) WriteHeader(code int) {
	rws := w.rws
	if rws == nil {
		panic("WriteHeader called after Handler finished")
	}
	rws.writeHeader(code)
}

func (rws *http2responseWriterState) writeHeader(code int) {
	if !rws.wroteHeader {
		http2checkWriteHeaderCode(code)
		rws.wroteHeader = true
		rws.status = code
		if len(rws.handlerHeader) > 0 {
			rws.snapHeader = http2cloneHeader(rws.handlerHeader)
		}
	}
}

func http2cloneHeader(h Header) Header {
	h2 := make(Header, len(h))
	for k, vv := range h {
		vv2 := make([]string, len(vv))
		copy(vv2, vv)
		h2[k] = vv2
	}
	return h2
}

// Write的生命是这样的：
// 
// /*处理程序调用w.Write或w.WriteString->
// /*->rws。bw（*bufio.Writer）->
// /*（处理程序可能会调用Flush）
// /*->chunkWriter{rws}
// /*->responseWriterState。writeChunk（p[]字节）
// /*->响应writerState。writeChunk（大部分魔法；请参见此处的注释）
func (w *http2responseWriter) Write(p []byte) (n int, err error) {
	return w.write(len(p), p, "")
}

func (w *http2responseWriter) WriteString(s string) (n int, err error) {
	return w.write(len(s), nil, s)
}

// DATA或DATA都不是零。
func (w *http2responseWriter) write(lenData int, dataB []byte, dataS string) (n int, err error) {
	rws := w.rws
	if rws == nil {
		panic("Write called after Handler finished")
	}
	if !rws.wroteHeader {
		w.WriteHeader(200)
	}
	if !http2bodyAllowedForStatus(rws.status) {
		return 0, ErrBodyNotAllowed
	}
	rws.wroteBytes += int64(len(dataB)) + int64(len(dataS)) // 只能设置一个
	if rws.sentContentLen != 0 && rws.wroteBytes > rws.sentContentLen {
		// TODO:发送RST_流
		return 0, errors.New("http2: handler wrote more than declared Content-Length")
	}

	if dataB != nil {
		return rws.bw.Write(dataB)
	} else {
		return rws.bw.WriteString(dataS)
	}
}

func (w *http2responseWriter) handlerDone() {
	rws := w.rws
	dirty := rws.dirty
	rws.handlerDone = true
	w.Flush()
	w.rws = nil
	if !dirty {
		// 只有在之前对
		// serverConn goroutine的所有写调用都成功完成时，才能回收池。如果
		// 由于来自对等方的重置，它们返回得更早
		// 可能仍有来自引用rws内存的serverConn的未完成写入goroutines 
		// 。参见
		// 第20704期。
		http2responseWriterStatePool.Put(rws)
	}
}

// 推送错误。
var (
	http2ErrRecursivePush    = errors.New("http2: recursive push not allowed")
	http2ErrPushLimitReached = errors.New("http2: push would exceed peer's SETTINGS_MAX_CONCURRENT_STREAMS")
)

var _ Pusher = (*http2responseWriter)(nil)

func (w *http2responseWriter) Push(target string, opts *PushOptions) error {
	st := w.rws.stream
	sc := st.sc
	sc.serveG.checkNotOn()

	// 无递归推送：“推送承诺帧只能在对等启动的流上发送。”
	// http:
	if st.isPushed() {
		return http2ErrRecursivePush
	}

	if opts == nil {
		opts = new(PushOptions)
	}

	// 默认选项。
	if opts.Method == "" {
		opts.Method = "GET"
	}
	if opts.Header == nil {
		opts.Header = Header{}
	}
	wantScheme := "http"
	if w.rws.req.TLS != nil {
		wantScheme = "https"
	}

	// 验证请求。
	u, err := url.Parse(target)
	if err != nil {
		return err
	}
	if u.Scheme == "" {
		if !strings.HasPrefix(target, "/") {
			return fmt.Errorf("target must be an absolute URL or an absolute path: %q", target)
		}
		u.Scheme = wantScheme
		u.Host = w.rws.req.Host
	} else {
		if u.Scheme != wantScheme {
			return fmt.Errorf("cannot push URL with scheme %q from request with scheme %q", u.Scheme, wantScheme)
		}
		if u.Host == "" {
			return errors.New("URL must have a host")
		}
	}
	for k := range opts.Header {
		if strings.HasPrefix(k, ":") {
			return fmt.Errorf("promised request headers cannot include pseudo header %q", k)
		}
		// 只有当请求有正文时，这些头才有意义，但PUSH_PROMISE请求不能有正文。
		// http:
		// 也不允许主机，因为承诺的URL必须是绝对的。
		if http2asciiEqualFold(k, "content-length") ||
			http2asciiEqualFold(k, "content-encoding") ||
			http2asciiEqualFold(k, "trailer") ||
			http2asciiEqualFold(k, "te") ||
			http2asciiEqualFold(k, "expect") ||
			http2asciiEqualFold(k, "host") {
			return fmt.Errorf("promised request headers cannot include %q", k)
		}
	}
	if err := http2checkValidHTTP2RequestHeaders(opts.Header); err != nil {
		return err
	}

	// RFC有效地限制了承诺的请求获取和发送：
	// “承诺的请求必须是可缓存的[GET、HEAD或POST]，并且必须是安全的[GET或HEAD]”
	// http:
	if opts.Method != "GET" && opts.Method != "HEAD" {
		return fmt.Errorf("method %q must be GET or HEAD", opts.Method)
	}

	msg := &http2startPushRequest{
		parent: st,
		method: opts.Method,
		url:    u,
		header: http2cloneHeader(opts.Header),
		done:   http2errChanPool.Get().(chan error),
	}

	select {
	case <-sc.doneServing:
		return http2errClientDisconnected
	case <-st.cw:
		return http2errStreamClosed
	case sc.serveMsgCh <- msg:
	}

	select {
	case <-sc.doneServing:
		return http2errClientDisconnected
	case <-st.cw:
		return http2errStreamClosed
	case err := <-msg.done:
		http2errChanPool.Put(msg.done)
		return err
	}
}

type http2startPushRequest struct {
	parent *http2stream
	method string
	url    *url.URL
	header Header
	done   chan error
}

func (sc *http2serverConn) startPush(msg *http2startPushRequest) {
	sc.serveG.check()

	// http:
	// PUSH_承诺帧必须仅在
	// 处于“开放”或“半关闭（远程）”状态。
	if msg.parent.state != http2stateOpen && msg.parent.state != http2stateHalfClosedRemote {
		// 回复作者。推送检查流是否由对等方发起。
		msg.done <- http2errStreamClosed
		return
	}

	// http:
	if !sc.pushEnabled {
		msg.done <- ErrNotSupported
		return
	}

	// 推送承诺帧必须按流ID的递增顺序发送，因此
	// 在写入推送承诺
	// 时，我们会为承诺流懒洋洋地分配一个ID。一旦分配了ID，我们就启动请求处理程序。
	allocatePromisedID := func() (uint32, error) {
		sc.serveG.check()

		// 请再次检查，以防万一。从技术上讲，我们可能已经收到了
		// 更新的设置，当我们开始写这个框架的时候。
		if !sc.pushEnabled {
			return 0, ErrNotSupported
		}
		// http:
		if sc.curPushedStreams+1 > sc.clientMaxStreams {
			return 0, http2ErrPushLimitReached
		}

		// http:
		// 服务器启动的流必须使用偶数标识符。
		// 无法建立新流标识符的服务器可以发送GOAWAY 
		// 帧，以便客户端被迫为新流打开新连接。
		if sc.maxPushPromiseID+2 >= 1<<31 {
			sc.startGracefulShutdownInternal()
			return 0, http2ErrPushLimitReached
		}
		sc.maxPushPromiseID += 2
		promisedID := sc.maxPushPromiseID

		// http:
		// 严格来说，新的流应该从“保留（本地）”开始，然后在发送初始头后转换到“半关闭（远程）”，但是为了简单起见，我们从“半关闭（远程）”开始。
		// 请参阅StateHalf ClosedRemote定义中的更多注释。
		promised := sc.newStream(promisedID, msg.parent.id, http2stateHalfClosedRemote)
		rw, req, err := sc.newWriterAndRequestNoBody(promised, http2requestParam{
			method:    msg.method,
			scheme:    msg.url.Scheme,
			authority: msg.url.Host,
			path:      msg.url.RequestURI(),
			header:    http2cloneHeader(msg.header), // 克隆因为处理程序与写入推送承诺同时运行
		})
		if err != nil {
			// 不应该发生，因为我们已经验证了msg。网址。
			panic(fmt.Sprintf("newWriterAndRequestNoBody(%+v): %v", msg.url, err))
		}

		go sc.runHandler(rw, req, sc.handler.ServeHTTP)
		return promisedID, nil
	}

	sc.writeFrame(http2FrameWriteRequest{
		write: &http2writePushPromise{
			streamID:           msg.parent.id,
			method:             msg.method,
			url:                msg.url,
			h:                  msg.header,
			allocatePromisedID: allocatePromisedID,
		},
		stream: msg.parent,
		done:   msg.done,
	})
}

// foreachHeaderElement根据RFC 7230第7节中的“#规则”构造
// 拆分v，并为每个非空元素调用fn。
func http2foreachHeaderElement(v string, fn func(string)) {
	v = textproto.TrimString(v)
	if v == "" {
		return
	}
	if !strings.Contains(v, ",") {
		fn(v)
		return
	}
	for _, f := range strings.Split(v, ",") {
		if f = textproto.TrimString(f); f != "" {
			fn(f)
		}
	}
}

// 来自http:
var http2connHeaders = []string{
	"Connection",
	"Keep-Alive",
	"Proxy-Connection",
	"Transfer-Encoding",
	"Upgrade",
}

// checkValidHTTP2RequestHeaders根据RFC 7540第8.1.2.2节检查h是否为有效的HTTP/2请求，
// 。
// 将返回的错误报告给用户。
func http2checkValidHTTP2RequestHeaders(h Header) error {
	for _, k := range http2connHeaders {
		if _, ok := h[k]; ok {
			return fmt.Errorf("request header %q is not valid in HTTP/2", k)
		}
	}
	te := h["Te"]
	if len(te) > 0 && (len(te) > 1 || (te[0] != "trailers" && te[0] != "")) {
		return errors.New(`request header "TE" may only be "trailers" in HTTP/2`)
	}
	return nil
}

func http2new400Handler(err error) HandlerFunc {
	return func(w ResponseWriter, r *Request) {
		Error(w, err.Error(), StatusBadRequest)
	}
}

// h1ServerKeepAlivesDisabled报告hs是否已禁用其保留。请参阅上面关于h1ServerShutdownChan的评论，了解
// 代码是这样编写的。
func http2h1ServerKeepAlivesDisabled(hs *Server) bool {
	var x interface{} = hs
	type I interface {
		doKeepAlives() bool
	}
	if hs, ok := x.(I); ok {
		return !hs.doKeepAlives()
	}
	return false
}

func (sc *http2serverConn) countError(name string, err error) error {
	if sc == nil || sc.srv == nil {
		return err
	}
	f := sc.srv.CountError
	if f == nil {
		return err
	}
	var typ string
	var code http2ErrCode
	switch e := err.(type) {
	case http2ConnectionError:
		typ = "conn"
		code = http2ErrCode(e)
	case http2StreamError:
		typ = "stream"
		code = http2ErrCode(e.Code)
	default:
		return err
	}
	codeStr := http2errCodeName[code]
	if codeStr == "" {
		codeStr = strconv.Itoa(int(code))
	}
	f(fmt.Sprintf("%s_%s_%s", typ, codeStr, name))
	return err
}

const (
	// transportDefaultConnFlow是我们在启动时为服务器提供的超过默认64k的连接级别流控制令牌数。
	http2transportDefaultConnFlow = 1 << 30

	// transportDefaultStreamFlow是我们向对等方宣布的流级流
	// 控制令牌的数量，以及
	// 我们每个流都有缓冲区。
	http2transportDefaultStreamFlow = 4 << 20

	// transportDefaultStreamMinRefresh是我们一次要发送的流级窗口更新的最小字节数。
	http2transportDefaultStreamMinRefresh = 4 << 10

	http2defaultUserAgent = "Go-http-client/2.0"

	// initialMaxConcurrentStreams是一个连接maxConcurrentStreams直到
	// 它的接收服务器初始设置帧，对应于
	// 规范的最小建议值。
	http2initialMaxConcurrentStreams = 100

	// defaultMaxConcurrentStreams是默认的连接maxConcurrentStreams 
	// 如果服务器在其初始设置框架中未包含连接。
	http2defaultMaxConcurrentStreams = 1000
)

// 传输是一种HTTP/2传输。
// 
// 传输在内部缓存到服务器的连接。
// 供多个Goroutine同时使用是安全的。
type http2Transport struct {
	// DialTLS指定一个可选的拨号函数，用于为请求创建
	// TLS连接。
	// 
	// 如果拨号为零，则为tls。使用拨号盘。
	// 
	// 如果返回的是网络。Conn有一个像tls一样的ConnectionState方法。Conn，
	// 它将用于设置http。回答TLS。
	DialTLS func(network, addr string, cfg *tls.Config) (net.Conn, error)

	// TLSClientConfig指定要与
	// TLS一起使用的TLS配置。客户如果为nil，则使用默认配置。
	TLSClientConfig *tls.Config

	// ConnPool可选地指定要使用的备用连接池。
	// 如果为零，则使用默认值。
	ConnPool http2ClientConnPool

	// DisableCompression，如果为true，则阻止传输
	// 在请求不包含现有
	// 请求头进行压缩。如果传输在
	// 接受编码值时，使用“接受编码：gzip”
	// 上请求gzip并得到gzipped响应，那么它在响应中透明地被
	// 解码。身体但是，如果用户
	// 明确请求gzip，则不会自动
	// 解压缩。
	DisableCompression bool

	// allowhtp，如果为true，则允许使用不安全的、
	// 纯文本“HTTP”方案的HTTP/2请求。请注意，这不会启用h2c支持。
	AllowHTTP bool

	// MaxHeaderListSize是在初始设置框中发送的http2设置\最大\头\列表\大小。它是允许响应头的字节数
	// 。与http2规范不同，这里的零
	// 意味着使用默认限制（当前为10MB）。如果您真的想向对等方公布一个无限制的值，Transport 
	// 将此处可能的最高值（0xffffff或1<<32-1）
	// 解释为无限制。
	MaxHeaderListSize uint32

	// StrictMaxConcurrentStreams控制服务器的
	// 设置是否应在全局范围内遵守最大并发流
	// 。如果为false，将根据需要创建到
	// 服务器的新TCP连接，以将每个连接保持在每个连接
	// 设置\u最大\u并发\u流限制之下。如果为true，则
	// 服务器的设置_MAX_CONCURRENT_STREAMS将被解释为
	// 一个全局限制和往返块的调用方（如果需要），
	// 等待轮到他们。
	StrictMaxConcurrentStreams bool

	// ReadIdleTimeout是超时，在此超时之后，如果连接上未接收到任何帧，将使用ping 
	// frame执行运行状况检查。
	// 请注意，ping响应将被视为接收到的帧，因此，如果连接上没有其他流量，则将在每个ReadIdleTimeout间隔执行健康检查。
	// 如果为零，则不执行健康检查。
	ReadIdleTimeout time.Duration

	// PingTimeout是超时，如果未收到Ping响应，则连接将在该超时后关闭。
	// 默认为15秒。
	PingTimeout time.Duration

	// WriteByteTimeout是连接将被关闭的超时时间
	// 无法向其写入数据。当数据
	// 可写入时，超时开始，并在写入任何字节时延长。
	WriteByteTimeout time.Duration

	// CountError，如果非nil，则在HTTP/2传输错误时调用。
	// 它旨在增加一个用于监控的度量，例如
	// 作为expvar或Prometheus度量。
	// 错误类型仅由ASCII字字符组成。
	CountError func(errType string)

	// t1，如果不是nil，则是使用
	// 此传输的标准库传输。使用其设置（但不使用其
	// 往返方法等）。
	t1 *Transport

	connPoolOnce  sync.Once
	connPoolOrDef http2ClientConnPool // 非零版本的ConnPool 
}

func (t *http2Transport) maxHeaderListSize() uint32 {
	if t.MaxHeaderListSize == 0 {
		return 10 << 20
	}
	if t.MaxHeaderListSize == 0xffffffff {
		return 0
	}
	return t.MaxHeaderListSize
}

func (t *http2Transport) disableCompression() bool {
	return t.DisableCompression || (t.t1 != nil && t.t1.DisableCompression)
}

func (t *http2Transport) pingTimeout() time.Duration {
	if t.PingTimeout == 0 {
		return 15 * time.Second
	}
	return t.PingTimeout

}

// 配置传输将net/http http/1传输配置为使用http/2。
// 如果t1已经启用HTTP/2，则返回一个错误。
// 
// 使用配置传输来配置HTTP/2传输。
func http2ConfigureTransport(t1 *Transport) error {
	_, err := http2ConfigureTransports(t1)
	return err
}

// ConfigureTransports将net/http http/1传输配置为使用http/2。
// 它返回一个新的HTTP/2传输以进行进一步配置。
// 如果t1已启用HTTP/2，则返回一个错误。
func http2ConfigureTransports(t1 *Transport) (*http2Transport, error) {
	return http2configureTransports(t1)
}

func http2configureTransports(t1 *Transport) (*http2Transport, error) {
	connPool := new(http2clientConnPool)
	t2 := &http2Transport{
		ConnPool: http2noDialClientConnPool{connPool},
		t1:       t1,
	}
	connPool.t = t2
	if err := http2registerHTTPSProtocol(t1, http2noDialH2RoundTripper{t2}); err != nil {
		return nil, err
	}
	if t1.TLSClientConfig == nil {
		t1.TLSClientConfig = new(tls.Config)
	}
	if !http2strSliceContains(t1.TLSClientConfig.NextProtos, "h2") {
		t1.TLSClientConfig.NextProtos = append([]string{"h2"}, t1.TLSClientConfig.NextProtos...)
	}
	if !http2strSliceContains(t1.TLSClientConfig.NextProtos, "http/1.1") {
		t1.TLSClientConfig.NextProtos = append(t1.TLSClientConfig.NextProtos, "http/1.1")
	}
	upgradeFn := func(authority string, c *tls.Conn) RoundTripper {
		addr := http2authorityAddr("https", authority)
		if used, err := connPool.addConnIfNeeded(addr, t2, c); err != nil {
			go c.Close()
			return http2erringRoundTripper{err}
		} else if !used {
			// 事实证明我们不需要这个c.
			// 例如，两个Goroutine同时向同一主机发出请求，两个Goroutine都启动了TCP拨号。（因为协议
			// 未知）
			go c.Close()
		}
		return t2
	}
	if m := t1.TLSNextProto; len(m) == 0 {
		t1.TLSNextProto = map[string]func(string, *tls.Conn) RoundTripper{
			"h2": upgradeFn,
		}
	} else {
		m["h2"] = upgradeFn
	}
	return t2, nil
}

func (t *http2Transport) connPool() http2ClientConnPool {
	t.connPoolOnce.Do(t.initConnPool)
	return t.connPoolOrDef
}

func (t *http2Transport) initConnPool() {
	if t.ConnPool != nil {
		t.connPoolOrDef = t.ConnPool
	} else {
		t.connPoolOrDef = &http2clientConnPool{t: t}
	}
}

// ClientConn是单个HTTP/2客户端连接到
// HTTP/2服务器的状态。
type http2ClientConn struct {
	t             *http2Transport
	tconn         net.Conn             // 通常是*tls。Conn，除专用IMPS 
	tlsState      *tls.ConnectionState // 无，仅适用于专用IMPS 
	reused        uint32               // Conn是否被重用；原子
	singleUse     bool                 // 是否用于单个http。请求
	getConnCalled bool                 // 由clientConnPool使用

	// readLoop goroutine字段：
	readerDone chan struct{} // 错误时关闭
	readerErr  error         // 在ReaderOne关闭前设置

	idleTimeout time.Duration // 或0表示从不
	idleTimer   *time.Timer

	mu              sync.Mutex // 在
	cond            *sync.Cond // 保持mu；流量/关闭更改广播
	flow            http2flow  // 我们的conn级别流量控制配额（cs.flow是每个流）
	inflow          http2flow  // 对等方的conn级别流量控制
	doNotReuse      bool       // 是否将conn标记为不可用于任何未来请求
	closing         bool
	closed          bool
	seenSettings    bool                          // 如果我们看到设置框架，false否则
	wantSettingsAck bool                          // 我们发送了一个设置帧，还没有收到回复
	goAway          *http2GoAwayFrame             // 如果非空，我们收到的门框
	goAwayDebug     string                        // 门框的调试数据，保留为字符串
	streams         map[uint32]*http2clientStream // 客户端通过ReserveNewRequest启动
	streamsReserved int                           // incr；decr on Round Trip 
	nextStreamID    uint32
	pendingRequests int                       // 请求被阻止并等待发送，因为len（streams）=maxConcurrentStreams 
	pings           map[[8]byte]chan struct{} // 飞行中ping数据到通知通道
	br              *bufio.Reader
	lastActive      time.Time
	lastIdle        time.Time // 上次空闲时间
	// 来自对等方的设置：（也由wmu保护）
	maxFrameSize          uint32
	maxConcurrentStreams  uint32
	peerMaxHeaderListSize uint64
	initialWindowSize     uint32

	// reqHeaderMu是一个1元素信号通道，控制对发送新数据的访问请求。
	// 写入reqHeaderMu以锁定它，读取它以解锁。
	// 在mu或wmu之前锁定reqmu。
	reqHeaderMu chan struct{}

	// wmu在书写时被持有。
	// 在同时持有mu之前获取，以避免在网络写入时阻塞mu。
	// 更改对等设置时，只能同时获取这两种设置。
	wmu  sync.Mutex
	bw   *bufio.Writer
	fr   *http2Framer
	werr error        // 发生的第一次写入错误
	hbuf bytes.Buffer // HPACK编码器写入此
	henc *hpack.Encoder
}

// clientStream是单个HTTP/2流的状态。其中一个
// 是为每个传输创建的。往返电话。
type http2clientStream struct {
	cc *http2ClientConn

	// 即使在响应主体关闭后，我们也可以访问的请求字段。
	ctx       context.Context
	reqCancel <-chan struct{}

	trace         *httptrace.ClientTrace // 或nil 
	ID            uint32
	bufPipe       http2pipe // 具有流控制响应有效负载的缓冲管道
	requestedGzip bool
	isHead        bool

	abortOnce sync.Once
	abort     chan struct{} // 关闭到信号流时应立即结束
	abortErr  error         // 如果abort关闭则设置

	peerClosed chan struct{} // 当对等方发送结束流标志
	donec      chan struct{} // 在流处于关闭状态后关闭
	on100      chan struct{} // 缓冲时关闭；如果收到100则写入

	respHeaderRecv chan struct{} // 当收到头时关闭
	res            *Response     // 如果respHeaderRecv关闭则设置

	flow        http2flow // 由cc保护。mu 
	inflow      http2flow // 由cc守卫。mu 
	bytesRemain int64     // /-1表示未知；由transportResponseBody所有。读取
	readErr     error     // 粘性读取错误；由transportResponseBody所有。Read 

	reqBody              io.ReadCloser
	reqBodyContentLength int64 // /-1表示未知
	reqBodyClosed        bool  // 车身已关闭；由cc守卫。mu 

	// 由WriterRequest所有：
	sentEndStream bool // 向对等方发送结束流标志
	sentHeaders   bool

	// 由clientConnReadLoop所有：
	firstByte    bool  // 获取第一个响应字节
	pastHeaders  bool  // 获取第一个MetaHeaderFrame（实际头）
	pastTrailers bool  // 获取可选的第二个MetaHeaderFrame（拖车）
	num1xx       uint8 // 1x响应数查看
	readClosed   bool  // 对等方发送了一个结束流标志
	readAborted  bool  // 读取循环重置流

	trailer    Header  // 
	resTrailer *Header // 客户端的响应。拖车
}

var http2got1xxFuncForTests func(int, textproto.MIMEHeader) error

// get1xxTraceFunc返回请求的httptrace的值。ClientTrace。Got1xxResponse func，
// 如果有。如果未设置或Go版本太旧，则返回nil。
func (cs *http2clientStream) get1xxTraceFunc() func(int, textproto.MIMEHeader) error {
	if fn := http2got1xxFuncForTests; fn != nil {
		return fn
	}
	return http2traceGot1xxResponseFunc(cs.trace)
}

func (cs *http2clientStream) abortStream(err error) {
	cs.cc.mu.Lock()
	defer cs.cc.mu.Unlock()
	cs.abortStreamLocked(err)
}

func (cs *http2clientStream) abortStreamLocked(err error) {
	cs.abortOnce.Do(func() {
		cs.abortErr = err
		close(cs.abort)
	})
	if cs.reqBody != nil && !cs.reqBodyClosed {
		cs.reqBody.Close()
		cs.reqBodyClosed = true
	}
	// TODO（dneil）：清理cs所在的测试。复写的副本。康德是零。
	if cs.cc.cond != nil {
		// 如果writeRequestBody正在等待流控制，请将其唤醒。
		cs.cc.cond.Broadcast()
	}
}

func (cs *http2clientStream) abortRequestBodyWrite() {
	cc := cs.cc
	cc.mu.Lock()
	defer cc.mu.Unlock()
	if cs.reqBody != nil && !cs.reqBodyClosed {
		cs.reqBody.Close()
		cs.reqBodyClosed = true
		cc.cond.Broadcast()
	}
}

type http2stickyErrWriter struct {
	conn    net.Conn
	timeout time.Duration
	err     *error
}

func (sew http2stickyErrWriter) Write(p []byte) (n int, err error) {
	if *sew.err != nil {
		return 0, *sew.err
	}
	for {
		if sew.timeout != 0 {
			sew.conn.SetWriteDeadline(time.Now().Add(sew.timeout))
		}
		nn, err := sew.conn.Write(p[n:])
		n += nn
		if n < len(p) && nn > 0 && errors.Is(err, os.ErrDeadlineExceeded) {
			// 只要我们取得进展，就继续延长最后期限。
			continue
		}
		if sew.timeout != 0 {
			sew.conn.SetWriteDeadline(time.Time{})
		}
		*sew.err = err
		return n, err
	}
}

// noCachedConnError是ErrNoCachedConn的具体类型，无论是用户的x/net/http2的绑定版本（在h2_bundle.go中使用重写的类型名）还是
// ，net/http都需要检测它。因此，它有一个唯一的方法名
// （ISHTTP2NoCachedConnector），net/http通过函数
// ISNoCachedConnector进行嗅探。
type http2noCachedConnError struct{}

func (http2noCachedConnError) IsHTTP2NoCachedConnError() {}

func (http2noCachedConnError) Error() string { return "http2: no cached connection was available" }

// isNoCachedConnError报告err的类型是noCachedConnError 
// 还是net/http2的h2_bundle中的等效重命名类型。去这两种类型
// 可以共存于同一个正在运行的程序中。
func http2isNoCachedConnError(err error) bool {
	_, ok := err.(interface{ IsHTTP2NoCachedConnError() })
	return ok
}

var http2ErrNoCachedConn error = http2noCachedConnError{}

// RoundTripOpt是用于传输的选项。RoundTripOpt方法。
type http2RoundTripOpt struct {
	// OnlyCachedConn控制RoundTripOpt是否可以创建新的TCP连接。如果设置为true且
	// 没有可用的缓存连接，RoundTripOpt 
	// 将返回ErrNoCachedConn。
	OnlyCachedConn bool
}

func (t *http2Transport) RoundTrip(req *Request) (*Response, error) {
	return t.RoundTripOpt(req, http2RoundTripOpt{})
}

// authorityAddr返回给定的权限（主机/IP，或主机：端口/IP:port）
// 并返回主机：端口。如果需要，将添加端口443。
func http2authorityAddr(scheme string, authority string) (addr string) {
	host, port, err := net.SplitHostPort(authority)
	if err != nil { // 权威机构没有端口
		port = "443"
		if scheme == "http" {
			port = "80"
		}
		host = authority
	}
	if a, err := idna.ToASCII(host); err == nil {
		host = a
	}
	// IPv6地址文字，没有端口：
	if strings.HasPrefix(host, "[") && strings.HasSuffix(host, "]") {
		return host + ":" + port
	}
	return net.JoinHostPort(host, port)
}

// RoundTripOpt类似于往返，但需要选项。
func (t *http2Transport) RoundTripOpt(req *Request, opt http2RoundTripOpt) (*Response, error) {
	if !(req.URL.Scheme == "https" || (req.URL.Scheme == "http" && t.AllowHTTP)) {
		return nil, errors.New("http2: unsupported scheme")
	}

	addr := http2authorityAddr(req.URL.Scheme, req.URL.Host)
	for retry := 0; ; retry++ {
		cc, err := t.connPool().GetClientConn(req, addr)
		if err != nil {
			t.vlogf("http2: Transport failed to get client conn for %s: %v", addr, err)
			return nil, err
		}
		reused := !atomic.CompareAndSwapUint32(&cc.reused, 0, 1)
		http2traceGotConn(req, cc, reused)
		res, err := cc.RoundTrip(req)
		if err != nil && retry <= 6 {
			if req, err = http2shouldRetryRequest(req, err); err == nil {
				// 第一次重试后，以10%的抖动进行指数退避。
				if retry == 0 {
					continue
				}
				backoff := float64(uint(1) << (uint(retry) - 1))
				backoff += backoff * (0.1 * mathrand.Float64())
				select {
				case <-time.After(time.Second * time.Duration(backoff)):
					continue
				case <-req.Context().Done():
					err = req.Context().Err()
				}
			}
		}
		if err != nil {
			t.vlogf("RoundTrip failure: %v", err)
			return nil, err
		}
		return res, nil
	}
}

// CloseIdleConnections关闭以前从以前的请求连接到现在处于空闲状态的所有连接。
// 它不会中断当前正在使用的任何连接。
func (t *http2Transport) CloseIdleConnections() {
	if cp, ok := t.connPool().(http2clientConnPoolIdleCloser); ok {
		cp.closeIdleConnections()
	}
}

var (
	http2errClientConnClosed    = errors.New("http2: client conn is closed")
	http2errClientConnUnusable  = errors.New("http2: client conn not usable")
	http2errClientConnGotGoAway = errors.New("http2: Transport received Server's graceful shutdown GOAWAY")
)

// shouldRetryRequest在请求无法获取
// 响应头时通过往返调用。它总是以非零错误调用。
// 返回重试请求（同一请求，或
// 修改的克隆），如果请求无法重放，则返回错误。
func http2shouldRetryRequest(req *Request, err error) (*Request, error) {
	if !http2canRetryError(err) {
		return nil, err
	}
	// 如果主体为nil（或http.NoBody），则可以安全地重用此请求及其主体。
	if req.Body == nil || req.Body == NoBody {
		return req, nil
	}

	// 如果请求主体可以通过可选的req重置回其原始
	// 状态。去吧，去吧。
	if req.GetBody != nil {
		body, err := req.GetBody()
		if err != nil {
			return nil, err
		}
		newReq := *req
		newReq.Body = body
		return &newReq, nil
	}

	// 请求。Body无法重置回开始，但我们似乎还没有开始读取它，所以直接重用请求。
	if err == http2errClientConnUnusable {
		return req, nil
	}

	return nil, fmt.Errorf("http2: Transport: cannot retry err [%v] after Request.Body was written; define Request.GetBody to avoid this error", err)
}

func http2canRetryError(err error) bool {
	if err == http2errClientConnUnusable || err == http2errClientConnGotGoAway {
		return true
	}
	if se, ok := err.(http2StreamError); ok {
		if se.Code == http2ErrCodeProtocol && se.Cause == http2errFromPeer {
			// 请参阅golang/go#47635，golang/go#42777 
			return true
		}
		return se.Code == http2ErrCodeRefusedStream
	}
	return false
}

func (t *http2Transport) dialClientConn(ctx context.Context, addr string, singleUse bool) (*http2ClientConn, error) {
	host, _, err := net.SplitHostPort(addr)
	if err != nil {
		return nil, err
	}
	tconn, err := t.dialTLS(ctx)("tcp", addr, t.newTLSConfig(host))
	if err != nil {
		return nil, err
	}
	return t.newClientConn(tconn, singleUse)
}

func (t *http2Transport) newTLSConfig(host string) *tls.Config {
	cfg := new(tls.Config)
	if t.TLSClientConfig != nil {
		*cfg = *t.TLSClientConfig.Clone()
	}
	if !http2strSliceContains(cfg.NextProtos, http2NextProtoTLS) {
		cfg.NextProtos = append([]string{http2NextProtoTLS}, cfg.NextProtos...)
	}
	if cfg.ServerName == "" {
		cfg.ServerName = host
	}
	return cfg
}

func (t *http2Transport) dialTLS(ctx context.Context) func(string, string, *tls.Config) (net.Conn, error) {
	if t.DialTLS != nil {
		return t.DialTLS
	}
	return func(network, addr string, cfg *tls.Config) (net.Conn, error) {
		tlsCn, err := t.dialTLSWithContext(ctx, network, addr, cfg)
		if err != nil {
			return nil, err
		}
		state := tlsCn.ConnectionState()
		if p := state.NegotiatedProtocol; p != http2NextProtoTLS {
			return nil, fmt.Errorf("http2: unexpected ALPN protocol %q; want %q", p, http2NextProtoTLS)
		}
		if !state.NegotiatedProtocolIsMutual {
			return nil, errors.New("http2: could not negotiate protocol mutually")
		}
		return tlsCn, nil
	}
}

// disableKeepAlives在处理第一个请求后尽快以
// 的形式报告是否应关闭连接。
func (t *http2Transport) disableKeepAlives() bool {
	return t.t1 != nil && t.t1.DisableKeepAlives
}

func (t *http2Transport) expectContinueTimeout() time.Duration {
	if t.t1 == nil {
		return 0
	}
	return t.t1.ExpectContinueTimeout
}

func (t *http2Transport) NewClientConn(c net.Conn) (*http2ClientConn, error) {
	return t.newClientConn(c, t.disableKeepAlives())
}

func (t *http2Transport) newClientConn(c net.Conn, singleUse bool) (*http2ClientConn, error) {
	cc := &http2ClientConn{
		t:                     t,
		tconn:                 c,
		readerDone:            make(chan struct{}),
		nextStreamID:          1,
		maxFrameSize:          16 << 10,                         // spec default 
		initialWindowSize:     65535,                            // spec default 
		maxConcurrentStreams:  http2initialMaxConcurrentStreams, // “无限”，根据规范使用较小的值，直到我们收到服务器设置。
		peerMaxHeaderListSize: 0xffffffffffffffff,               // /“无限”，根据规范。使用2^64-1代替。
		streams:               make(map[uint32]*http2clientStream),
		singleUse:             singleUse,
		wantSettingsAck:       true,
		pings:                 make(map[[8]byte]chan struct{}),
		reqHeaderMu:           make(chan struct{}, 1),
	}
	if d := t.idleConnTimeout(); d != 0 {
		cc.idleTimeout = d
		cc.idleTimer = time.AfterFunc(d, cc.onIdleTimeout)
	}
	if http2VerboseLogs {
		t.vlogf("http2: Transport creating client conn %p to %v", cc, c.RemoteAddr())
	}

	cc.cond = sync.NewCond(&cc.mu)
	cc.flow.add(int32(http2initialWindowSize))

	// TODO:调整此写入程序大小以考虑帧大小+
	// MTU+crypto/tls记录填充。
	cc.bw = bufio.NewWriter(http2stickyErrWriter{
		conn:    c,
		timeout: t.WriteByteTimeout,
		err:     &cc.werr,
	})
	cc.br = bufio.NewReader(c)
	cc.fr = http2NewFramer(cc.bw, cc.br)
	if t.CountError != nil {
		cc.fr.countError = t.CountError
	}
	cc.fr.ReadMetaHeaders = hpack.NewDecoder(http2initialHeaderTableSize, nil)
	cc.fr.MaxHeaderListSize = t.maxHeaderListSize()

	// TODO:SetMaxDynamicTableSize，SetMaxDynamicTableSizeLimit on 
	// henc响应设置帧？
	cc.henc = hpack.NewEncoder(&cc.hbuf)

	if t.AllowHTTP {
		cc.nextStreamID = 3
	}

	if cs, ok := c.(http2connectionStater); ok {
		state := cs.ConnectionState()
		cc.tlsState = &state
	}

	initialSettings := []http2Setting{
		{ID: http2SettingEnablePush, Val: 0},
		{ID: http2SettingInitialWindowSize, Val: http2transportDefaultStreamFlow},
	}
	if max := t.maxHeaderListSize(); max != 0 {
		initialSettings = append(initialSettings, http2Setting{ID: http2SettingMaxHeaderListSize, Val: max})
	}

	cc.bw.Write(http2clientPreface)
	cc.fr.WriteSettings(initialSettings...)
	cc.fr.WriteWindowUpdate(0, http2transportDefaultConnFlow)
	cc.inflow.add(http2transportDefaultConnFlow + http2initialWindowSize)
	cc.bw.Flush()
	if cc.werr != nil {
		cc.Close()
		return nil, cc.werr
	}

	go cc.readLoop()
	return cc, nil
}

func (cc *http2ClientConn) healthCheck() {
	pingTimeout := cc.t.pingTimeout()
	// 我们不需要在运行状况检查中定期ping，因为ClientConn的readLoop将在没有收到帧的情况下再次触发运行状况检查。
	ctx, cancel := context.WithTimeout(context.Background(), pingTimeout)
	defer cancel()
	err := cc.Ping(ctx)
	if err != nil {
		cc.closeForLostPing()
		cc.t.connPool().MarkDead(cc)
		return
	}
}

// SetDoNotReuse将cc标记为不可用于将来的HTTP请求。
func (cc *http2ClientConn) SetDoNotReuse() {
	cc.mu.Lock()
	defer cc.mu.Unlock()
	cc.doNotReuse = true
}

func (cc *http2ClientConn) setGoAway(f *http2GoAwayFrame) {
	cc.mu.Lock()
	defer cc.mu.Unlock()

	old := cc.goAway
	cc.goAway = f

	// 合并之前和当前的GoAway错误帧。
	if cc.goAwayDebug == "" {
		cc.goAwayDebug = string(f.DebugData())
	}
	if old != nil && old.ErrCode != http2ErrCodeNo {
		cc.goAway.ErrCode = old.ErrCode
	}
	last := f.LastStreamID
	for streamID, cs := range cc.streams {
		if streamID > last {
			cs.abortStreamLocked(http2errClientConnGotGoAway)
		}
	}
}

// CanTakeNewRequest报告连接是否可以接受新请求，
// 表示连接尚未关闭或接收或发送。
// 
// 如果调用者要立即在此
// 连接上发出新请求，请改用ReserveNewRequest。
func (cc *http2ClientConn) CanTakeNewRequest() bool {
	cc.mu.Lock()
	defer cc.mu.Unlock()
	return cc.canTakeNewRequestLocked()
}

// ReserveNewRequest类似于CanTakeNewRequest，但也在cc中保留了一个
// 并发流。在
// 下一次往返通话中，预订量将减少。
func (cc *http2ClientConn) ReserveNewRequest() bool {
	cc.mu.Lock()
	defer cc.mu.Unlock()
	if st := cc.idleStateLocked(); !st.canTakeNewRequest {
		return false
	}
	cc.streamsReserved++
	return true
}

// ClientConnState描述ClientConn的状态。
type http2ClientConnState struct {
	// 关闭是指连接是否关闭。
	Closed bool

	// 关闭是指连接是否正在关闭。它可能因关机而关闭，是一个
	// 一次性连接，被标记为DoNotReuse，或
	// 已收到球门框架。
	Closing bool

	// StreamsActive是有多少流处于活动状态。
	StreamsActive int

	// StreamsReserved是通过
	// ClientConn保留的流数。保留新请求。
	StreamsReserved int

	// StreamsPending是发送的请求数超过了对等方公布的MaxConcurrentStreams设置和
	// 正在等待其他流完成。
	StreamsPending int

	// MaxConcurrentStreams是
	// peer公布为可接受的并发流的数量。零表示尚未收到任何设置
	// 帧。
	MaxConcurrentStreams uint32

	// LastIdle，如果非零，则表示连接最后一次
	// 转换为空闲状态。
	LastIdle time.Time
}

// 状态返回cc状态的快照。
func (cc *http2ClientConn) State() http2ClientConnState {
	cc.wmu.Lock()
	maxConcurrent := cc.maxConcurrentStreams
	if !cc.seenSettings {
		maxConcurrent = 0
	}
	cc.wmu.Unlock()

	cc.mu.Lock()
	defer cc.mu.Unlock()
	return http2ClientConnState{
		Closed:               cc.closed,
		Closing:              cc.closing || cc.singleUse || cc.doNotReuse || cc.goAway != nil,
		StreamsActive:        len(cc.streams),
		StreamsReserved:      cc.streamsReserved,
		StreamsPending:       cc.pendingRequests,
		LastIdle:             cc.lastIdle,
		MaxConcurrentStreams: maxConcurrent,
	}
}

// ClientConnidEstate描述了客户端
// 连接是否适合发起新的往返请求。
type http2clientConnIdleState struct {
	canTakeNewRequest bool
}

func (cc *http2ClientConn) idleState() http2clientConnIdleState {
	cc.mu.Lock()
	defer cc.mu.Unlock()
	return cc.idleStateLocked()
}

func (cc *http2ClientConn) idleStateLocked() (st http2clientConnIdleState) {
	if cc.singleUse && cc.nextStreamID > 1 {
		return
	}
	var maxConcurrentOkay bool
	if cc.t.StrictMaxConcurrentStreams {
		// 我们会告诉呼叫者我们可以向
		// 接收一个新请求，阻止呼叫者拨打一个新的TCP 
		// 连接，但稍后我们会在
		// 写入之前阻止它。
		maxConcurrentOkay = true
	} else {
		maxConcurrentOkay = int64(len(cc.streams)+cc.streamsReserved+1) <= int64(cc.maxConcurrentStreams)
	}

	st.canTakeNewRequest = cc.goAway == nil && !cc.closed && !cc.closing && maxConcurrentOkay &&
		!cc.doNotReuse &&
		int64(cc.nextStreamID)+2*int64(cc.pendingRequests) < math.MaxInt32 &&
		!cc.tooIdleLocked()
	return
}

func (cc *http2ClientConn) canTakeNewRequestLocked() bool {
	st := cc.idleStateLocked()
	return st.canTakeNewRequest
}

// tooIdleLocked报告此连接是否已闲置了太多时间。
func (cc *http2ClientConn) tooIdleLocked() bool {
	// 圆形（0）带单音时钟读数，因此
	// 时间根据其壁时间进行比较。我们不希望
	// 重复使用在
	// VM/笔记本电脑暂停期间处于空闲状态的连接，如果单调时间也被冻结。
	return cc.idleTimeout != 0 && !cc.lastIdle.IsZero() && time.Since(cc.lastIdle.Round(0)) > cc.idleTimeout
}

// onIdleTimeout是从一个时间调用的。AfterFunc goroutine。它将只在我们空闲时被调用，但是因为我们来自一个新的
// goroutine，可能同时有一个新的请求，
// ，所以这只是调用同步关闭文件来关闭这个
// 连接。计时器可以直接调用closeIfIdle，但这更清楚。
func (cc *http2ClientConn) onIdleTimeout() {
	cc.closeIfIdle()
}

func (cc *http2ClientConn) closeIfIdle() {
	cc.mu.Lock()
	if len(cc.streams) > 0 || cc.streamsReserved > 0 {
		cc.mu.Unlock()
		return
	}
	cc.closed = true
	nextID := cc.nextStreamID
	// 待办事项：客户是否也发送GOAWAY？大概只需关闭：
	cc.mu.Unlock()

	if http2VerboseLogs {
		cc.vlogf("http2: Transport closing idle conn %p (forSingleUse=%v, maxStream=%v)", cc, cc.singleUse, nextID-2)
	}
	cc.tconn.Close()
}

func (cc *http2ClientConn) isDoNotReuseAndIdle() bool {
	cc.mu.Lock()
	defer cc.mu.Unlock()
	return cc.doNotReuse && len(cc.streams) == 0
}

var http2shutdownEnterWaitStateHook = func() {}

// Shutdown优雅地关闭客户端连接，等待运行的流完成。
func (cc *http2ClientConn) Shutdown(ctx context.Context) error {
	if err := cc.sendGoAway(); err != nil {
		return err
	}
	// 等待所有飞行流完成或连接关闭
	done := make(chan error, 1)
	cancelled := false // 由cc保护。mu 
	go func() {
		cc.mu.Lock()
		defer cc.mu.Unlock()
		for {
			if len(cc.streams) == 0 || cc.closed {
				cc.closed = true
				done <- cc.tconn.Close()
				break
			}
			if cancelled {
				break
			}
			cc.cond.Wait()
		}
	}()
	http2shutdownEnterWaitStateHook()
	select {
	case err := <-done:
		return err
	case <-ctx.Done():
		cc.mu.Lock()
		// 释放
		cancelled = true
		cc.cond.Broadcast()
		cc.mu.Unlock()
		return ctx.Err()
	}
}

func (cc *http2ClientConn) sendGoAway() error {
	cc.mu.Lock()
	closing := cc.closing
	cc.closing = true
	maxStreamID := cc.nextStreamID
	cc.mu.Unlock()
	if closing {
		// GOAWAY已发送
		return nil
	}

	cc.wmu.Lock()
	defer cc.wmu.Unlock()
	// 向服务器发送优雅的关闭帧
	if err := cc.fr.WriteGoAway(maxStreamID, http2ErrCodeNo, nil); err != nil {
		return err
	}
	if err := cc.bw.Flush(); err != nil {
		return err
	}
	// 防止新请求
	return nil
}

// 立即关闭客户端连接。飞行中的请求被中断。
// 错误被发送到流。
func (cc *http2ClientConn) closeForError(err error) error {
	cc.mu.Lock()
	cc.closed = true
	for _, cs := range cc.streams {
		cs.abortStreamLocked(err)
	}
	defer cc.cond.Broadcast()
	defer cc.mu.Unlock()
	return cc.tconn.Close()
}

// 关闭立即关闭客户端连接。
// 
// 飞行中的请求被中断。要实现优雅的关机，请改用shutdown。
func (cc *http2ClientConn) Close() error {
	err := errors.New("http2: client connection force closed via ClientConn.Close")
	return cc.closeForError(err)
}

// 立即关闭客户端连接。飞行中的请求被中断。
func (cc *http2ClientConn) closeForLostPing() error {
	err := errors.New("http2: client connection lost")
	if f := cc.t.CountError; f != nil {
		f("conn_close_lost_ping")
	}
	return cc.closeForError(err)
}

// errrequestcancelled是net/http的errrequestcancelled的副本，因为它不是
// 导出的。至少在h1-vs-h2比较测试中，它们是相等的。
var http2errRequestCanceled = errors.New("net/http: request canceled")

func http2commaSeparatedTrailers(req *Request) (string, error) {
	keys := make([]string, 0, len(req.Trailer))
	for k := range req.Trailer {
		k = CanonicalHeaderKey(k)
		switch k {
		case "Transfer-Encoding", "Trailer", "Content-Length":
			return "", fmt.Errorf("invalid Trailer key %q", k)
		}
		keys = append(keys, k)
	}
	if len(keys) > 0 {
		sort.Strings(keys)
		return strings.Join(keys, ","), nil
	}
	return "", nil
}

func (cc *http2ClientConn) responseHeaderTimeout() time.Duration {
	if cc.t.t1 != nil {
		return cc.t.t1.ResponseHeaderTimeout
	}
	// 还没有办法做到这一点吗只有一个http2。运输可能是
	// 没必要。要求取消这是新的方式。我们只需要支持
	// 这是为了与旧的http兼容。当
	// 我们在做透明的http2时，传输字段。
	return 0
}

// checkConnHeaders检查req是否有任何无效的连接级别头。
// 根据RFC 7540第8.1.2.2节：特定于连接的头字段。
// 某些头的大小写为OK，但不会在以后传输。
func http2checkConnHeaders(req *Request) error {
	if v := req.Header.Get("Upgrade"); v != "" {
		return fmt.Errorf("http2: invalid Upgrade request header: %q", req.Header["Upgrade"])
	}
	if vv := req.Header["Transfer-Encoding"]; len(vv) > 0 && (len(vv) > 1 || vv[0] != "" && vv[0] != "chunked") {
		return fmt.Errorf("http2: invalid Transfer-Encoding request header: %q", vv)
	}
	if vv := req.Header["Connection"]; len(vv) > 0 && (len(vv) > 1 || vv[0] != "" && !http2asciiEqualFold(vv[0], "close") && !http2asciiEqualFold(vv[0], "keep-alive")) {
		return fmt.Errorf("http2: invalid Connection request header: %q", vv)
	}
	return nil
}

// actualContentLength返回经过消毒的
// req版本。ContentLength，其中0实际上表示零（非未知），而-1 
// 表示未知。
func http2actualContentLength(req *Request) int64 {
	if req.Body == nil || req.Body == NoBody {
		return 0
	}
	if req.ContentLength != 0 {
		return req.ContentLength
	}
	return -1
}

func (cc *http2ClientConn) decrStreamReservations() {
	cc.mu.Lock()
	defer cc.mu.Unlock()
	cc.decrStreamReservationsLocked()
}

func (cc *http2ClientConn) decrStreamReservationsLocked() {
	if cc.streamsReserved > 0 {
		cc.streamsReserved--
	}
}

func (cc *http2ClientConn) RoundTrip(req *Request) (*Response, error) {
	ctx := req.Context()
	cs := &http2clientStream{
		cc:                   cc,
		ctx:                  ctx,
		reqCancel:            req.Cancel,
		isHead:               req.Method == "HEAD",
		reqBody:              req.Body,
		reqBodyContentLength: http2actualContentLength(req),
		trace:                httptrace.ContextClientTrace(ctx),
		peerClosed:           make(chan struct{}),
		abort:                make(chan struct{}),
		respHeaderRecv:       make(chan struct{}),
		donec:                make(chan struct{}),
	}
	go cs.doRequest(req)

	waitDone := func() error {
		select {
		case <-cs.donec:
			return nil
		case <-ctx.Done():
			return ctx.Err()
		case <-cs.reqCancel:
			return http2errRequestCanceled
		}
	}

	handleResponseHeaders := func() (*Response, error) {
		res := cs.res
		if res.StatusCode > 299 {
			// 关于错误或状态代码3xx、4xx、5xx等中止任何
			// 正在进行的写入，假设服务器不关心我们的请求体。但是，如果服务器回复为1xx或
			// 2xx，则假设服务器确实可能想要我们的身体（例如全双工流：
			// golang.org/issue/13444）。如果服务器
			// 没有，他们很快就会给我们发送流媒体。这是一个
			// 避免在运输中添加旋钮的启发式方法。希望我们能保留它。
			cs.abortRequestBodyWrite()
		}
		res.Request = req
		res.TLS = cc.tlsState
		if res.Body == http2noBody && http2actualContentLength(req) == 0 {
			// 如果没有请求或响应正文仍在写入
			// 请等待流关闭，然后再返回
			// 往返。
			if err := waitDone(); err != nil {
				return nil, err
			}
		}
		return res, nil
	}

	for {
		select {
		case <-cs.respHeaderRecv:
			return handleResponseHeaders()
		case <-cs.abort:
			select {
			case <-cs.respHeaderRecv:
				// 如果两个都是cs。resphaderrecv和cs。abort正在发信号，
				// 拾取应答器。服务器可能编写了
				// 响应，并立即重置流。
				// golang。org/issue/49645 
				return handleResponseHeaders()
			default:
				waitDone()
				return nil, cs.abortErr
			}
		case <-ctx.Done():
			err := ctx.Err()
			cs.abortStream(err)
			return nil, err
		case <-cs.reqCancel:
			cs.abortStream(http2errRequestCanceled)
			return nil, http2errRequestCanceled
		}
	}
}

// doRequest在请求生存期内运行。
// 
// 它发送请求并执行请求后清理（关闭request.Body等）。
func (cs *http2clientStream) doRequest(req *Request) {
	err := cs.writeRequest(req)
	cs.cleanupWriteRequest(err)
}

// writeRequest发送请求。
// 
// 在写入请求、读取响应、
// 并且请求流被对等方半关闭后返回nil。
// 
// 如果请求以其他方式结束，则返回非零。
// 如果返回的错误是StreamError，则错误代码可用于重置流。
func (cs *http2clientStream) writeRequest(req *Request) (err error) {
	cc := cs.cc
	ctx := cs.ctx

	if err := http2checkConnHeaders(req); err != nil {
		return err
	}

	// 通过写入reqHeaderMu获取新的请求锁。
	// 此锁保护关键部分，包括分配新流ID 
	// （需要mu）和创建流（需要wmu）。
	if cc.reqHeaderMu == nil {
		panic("RoundTrip on uninitialized ClientConn") // 用于测试
	}
	select {
	case cc.reqHeaderMu <- struct{}{}:
	case <-cs.reqCancel:
		return http2errRequestCanceled
	case <-ctx.Done():
		return ctx.Err()
	}

	cc.mu.Lock()
	if cc.idleTimer != nil {
		cc.idleTimer.Stop()
	}
	cc.decrStreamReservationsLocked()
	if err := cc.awaitOpenSlotForStreamLocked(cs); err != nil {
		cc.mu.Unlock()
		<-cc.reqHeaderMu
		return err
	}
	cc.addStreamLocked(cs) // 分配流ID 
	if http2isConnectionCloseRequest(req) {
		cc.doNotReuse = true
	}
	cc.mu.Unlock()

	// TODO（bradfitz）：这是net/http中逻辑的副本。在什么地方统一？
	if !cc.t.disableCompression() &&
		req.Header.Get("Accept-Encoding") == "" &&
		req.Header.Get("Range") == "" &&
		!cs.isHead {
		// 仅请求gzip，不请求泄气。Deflate模棱两可，
		// 无论如何都没有得到普遍支持。
		// 请参见：https:
		// 
		// 注意，我们不请求HEAD请求，
		// 由于nginx中的一个错误：
		// http:
		// https:
		// 
		// 如果请求的范围很广，我们不请求gzip，因为自动解码Gzip文档的一部分会失败。请参阅https:
		cs.requestedGzip = true
	}

	continueTimeout := cc.t.expectContinueTimeout()
	if continueTimeout != 0 {
		if !httpguts.HeaderValuesContainsToken(req.Header["Expect"], "100-continue") {
			continueTimeout = 0
		} else {
			cs.on100 = make(chan struct{}, 1)
		}
	}

	// 超过此点（我们在此处发送请求头），
	// 往返可能会成功返回。由于往返合同允许调用方在关闭响应主体后“修改或重用”请求，因此从现在开始引用请求时必须小心。
	err = cs.encodeAndWriteHeaders(req)
	<-cc.reqHeaderMu
	if err != nil {
		return err
	}

	hasBody := cs.reqBodyContentLength != 0
	if !hasBody {
		cs.sentEndStream = true
	} else {
		if continueTimeout != 0 {
			http2traceWait100Continue(cs.trace)
			timer := time.NewTimer(continueTimeout)
			select {
			case <-timer.C:
				err = nil
			case <-cs.on100:
				err = nil
			case <-cs.abort:
				err = cs.abortErr
			case <-ctx.Done():
				err = ctx.Err()
			case <-cs.reqCancel:
				err = http2errRequestCanceled
			}
			timer.Stop()
			if err != nil {
				http2traceWroteRequest(cs.trace, err)
				return err
			}
		}

		if err = cs.writeRequestBody(req); err != nil {
			if err != http2errStopReqBodyWrite {
				http2traceWroteRequest(cs.trace, err)
				return err
			}
		} else {
			cs.sentEndStream = true
		}
	}

	http2traceWroteRequest(cs.trace, err)

	var respHeaderTimer <-chan time.Time
	var respHeaderRecv chan struct{}
	if d := cc.responseHeaderTimeout(); d != 0 {
		timer := time.NewTimer(d)
		defer timer.Stop()
		respHeaderTimer = timer.C
		respHeaderRecv = cs.respHeaderRecv
	}
	// 等待对等端关闭其流的结尾，
	// 或直到请求被中止（通过上下文、错误或其他方式），
	// 以先到者为准。
	for {
		select {
		case <-cs.peerClosed:
			return nil
		case <-respHeaderTimer:
			return http2errTimeout
		case <-respHeaderRecv:
			respHeaderRecv = nil
			respHeaderTimer = nil // 如果在等待cc时请求被取消，请继续等待结束_流
		case <-cs.abort:
			return cs.abortErr
		case <-ctx.Done():
			return ctx.Err()
		case <-cs.reqCancel:
			return http2errRequestCanceled
		}
	}
}

func (cs *http2clientStream) encodeAndWriteHeaders(req *Request) error {
	cc := cs.cc
	ctx := cs.ctx

	cc.wmu.Lock()
	defer cc.wmu.Unlock()

	// 如果请求被取消。穆，退出吧。
	select {
	case <-cs.abort:
		return cs.abortErr
	case <-ctx.Done():
		return ctx.Err()
	case <-cs.reqCancel:
		return http2errRequestCanceled
	default:
	}

	// 对标题进行编码。
	// 
	// 我们发送：头{1}，继续{0，}+数据{0，}（数据是
	// 由下面的WritereRequestBody发送，以及任何预告，
	// 再次以头{1}，继续{0，}）的形式发送
	trailers, err := http2commaSeparatedTrailers(req)
	if err != nil {
		return err
	}
	hasTrailers := trailers != ""
	contentLen := http2actualContentLength(req)
	hasBody := contentLen != 0
	hdrs, err := cc.encodeHeaders(req, cs.requestedGzip, trailers, contentLen)
	if err != nil {
		return err
	}

	// 编写请求。
	endStream := !hasBody && !hasTrailers
	cs.sentHeaders = true
	err = cc.writeHeaders(cs.ID, endStream, int(cc.maxFrameSize), hdrs)
	http2traceWroteHeaders(cs.trace)
	return err
}

// cleanupWriteRequest执行请求后任务。
// 
// 如果err（writeRequest的结果）为非零且流未关闭，
// cleanupWriteRequest将向对等方发送重置。
func (cs *http2clientStream) cleanupWriteRequest(err error) {
	cc := cs.cc

	if cs.ID == 0 {
		// 我们在创建流之前被取消了，所以请返回我们的预订。
		cc.decrStreamReservations()
	}

	// TODO:编写H12比较测试，显示
	// 是否请求。Body被传输关闭，
	// 并且在多种情况下：服务器回复<=299和>299 
	// 同时仍在写入请求Body 
	cc.mu.Lock()
	bodyClosed := cs.reqBodyClosed
	cs.reqBodyClosed = true
	cc.mu.Unlock()
	if !bodyClosed && cs.reqBody != nil {
		cs.reqBody.Close()
	}

	if err != nil && cs.sentEndStream {
		// 如果在读取响应后立即关闭连接，
		// 我们可能会在结束之前中止。如果流在两侧完全关闭
		// 则没有错误。
		select {
		case <-cs.peerClosed:
			err = nil
		default:
		}
	}
	if err != nil {
		cs.abortStream(err) // 可能是多余的，但无害的
		if cs.sentHeaders {
			if se, ok := err.(http2StreamError); ok {
				if se.Cause != http2errFromPeer {
					cc.writeStreamReset(cs.ID, se.Code, err)
				}
			} else {
				cc.writeStreamReset(cs.ID, http2ErrCodeCancel, err)
			}
		}
		cs.bufPipe.CloseWithError(err) // 如果已经关闭，则无操作
	} else {
		if cs.sentHeaders && !cs.sentEndStream {
			cc.writeStreamReset(cs.ID, http2ErrCodeNo, nil)
		}
		cs.bufPipe.CloseWithError(http2errRequestCanceled)
	}
	if cs.ID != 0 {
		cc.forgetStreamID(cs.ID)
	}

	cc.wmu.Lock()
	werr := cc.werr
	cc.wmu.Unlock()
	if werr != nil {
		cc.Close()
	}

	close(cs.donec)
}

// 等待OpenSlotForStream等待len（streams）<maxConcurrentStreams。
// 必须持有cc。穆。
func (cc *http2ClientConn) awaitOpenSlotForStreamLocked(cs *http2clientStream) error {
	for {
		cc.lastActive = time.Now()
		if cc.closed || !cc.canTakeNewRequestLocked() {
			return http2errClientConnUnusable
		}
		cc.lastIdle = time.Time{}
		if int64(len(cc.streams)) < int64(cc.maxConcurrentStreams) {
			return nil
		}
		cc.pendingRequests++
		cc.cond.Wait()
		cc.pendingRequests--
		select {
		case <-cs.abort:
			return cs.abortErr
		default:
		}
	}
}

// 需要抄送。wmu be HOLD 
func (cc *http2ClientConn) writeHeaders(streamID uint32, endStream bool, maxFrameSize int, hdrs []byte) error {
	first := true // 写入的第一帧（首先是标题，然后是继续）
	for len(hdrs) > 0 && cc.werr == nil {
		chunk := hdrs
		if len(chunk) > maxFrameSize {
			chunk = chunk[:maxFrameSize]
		}
		hdrs = hdrs[len(chunk):]
		endHeaders := len(hdrs) == 0
		if first {
			cc.fr.WriteHeaders(http2HeadersFrameParam{
				StreamID:      streamID,
				BlockFragment: chunk,
				EndStream:     endStream,
				EndHeaders:    endHeaders,
			})
			first = false
		} else {
			cc.fr.WriteContinuation(streamID, endHeaders, chunk)
		}
	}
	cc.bw.Flush()
	return cc.werr
}

// 内部错误值；它们不会逃逸到调用方
var (
	// 中止请求体写入；不发送取消
	http2errStopReqBodyWrite = errors.New("http2: aborting request body write")

	// 中止请求正文写入，但发送取消的流重置。
	http2errStopReqBodyWriteAndCancel = errors.New("http2: canceling request")

	http2errReqBodyTooLong = errors.New("http2: request body larger than specified content length")
)

// frameScratchBufferLen返回用于
// 要读取/写入的传出请求正文的缓冲区长度。
// 
// 返回最大值（1，最小值（对等方公布的最大帧大小，
// Request.ContentLength+1512kb））。
func (cs *http2clientStream) frameScratchBufferLen(maxFrameSize int) int {
	const max = 512 << 10
	n := int64(maxFrameSize)
	if n > max {
		n = max
	}
	if cl := cs.reqBodyContentLength; cl != -1 && cl+1 < n {
		// 向
		// 添加超出声明内容长度的额外字节，给出调用方的请求。身体io。读者有机会看到
		// 给我们的字节比他们声明的要多，这样我们就可以尽早看到
		// 了。
		n = cl + 1
	}
	if n < 1 {
		return 1
	}
	return int(n) // 不截断；最大值为512K 
}

var http2bufPool sync.Pool // 共*[]字节

func (cs *http2clientStream) writeRequestBody(req *Request) (err error) {
	cc := cs.cc
	body := cs.reqBody
	sentEnd := false // 是否发送了最终数据帧w/END_流

	hasTrailers := req.Trailer != nil
	remainLen := cs.reqBodyContentLength
	hasContentLen := remainLen != -1

	cc.mu.Lock()
	maxFrameSize := int(cc.maxFrameSize)
	cc.mu.Unlock()

	// 用于读写的暂存缓冲区。
	scratchLen := cs.frameScratchBufferLen(maxFrameSize)
	var buf []byte
	if bp, ok := http2bufPool.Get().(*[]byte); ok && len(*bp) >= scratchLen {
		defer http2bufPool.Put(bp)
		buf = *bp
	} else {
		buf = make([]byte, scratchLen)
		defer http2bufPool.Put(&buf)
	}

	var sawEOF bool
	for !sawEOF {
		n, err := body.Read(buf[:len(buf)])
		if hasContentLen {
			remainLen -= int64(n)
			if remainLen == 0 && err == nil {
				// 请求正文的内容长度是预先声明的，
				// 我们刚刚读完所有内容，但基本的io。Reader 
				// 返回了带有nil错误的最后一个块（这是
				// 读者在EOF中可以做的两件有效的事情）。因为我们更希望
				// 提前发送结束流位，所以请仔细检查我们在EOF时是否确实是
				// 的。此时，后续读取应返回（0，EOF）。
				// 如果其中一个值不同，我们将通过以下两种方式之一返回错误。
				var scratch [1]byte
				var n1 int
				n1, err = body.Read(scratch[:])
				remainLen -= int64(n1)
			}
			if remainLen < 0 {
				err = http2errReqBodyTooLong
				return err
			}
		}
		if err != nil {
			cc.mu.Lock()
			bodyClosed := cs.reqBodyClosed
			cc.mu.Unlock()
			switch {
			case bodyClosed:
				return http2errStopReqBodyWrite
			case err == io.EOF:
				sawEOF = true
				err = nil
			default:
				return err
			}
		}

		remain := buf[:n]
		for len(remain) > 0 && err == nil {
			var allowed int32
			allowed, err = cs.awaitFlowControl(len(remain))
			if err != nil {
				return err
			}
			cc.wmu.Lock()
			data := remain[:allowed]
			remain = remain[allowed:]
			sentEnd = sawEOF && len(remain) == 0 && !hasTrailers
			err = cc.fr.WriteData(cs.ID, sentEnd, data)
			if err == nil {
				// TODO（bradfitz）：这个刷新是为了延迟，而不是带宽。
				// 大多数请求都不需要这个。选择加入还是退出？在体型上使用一些启发？Nagel喜欢
				// 计时器？基于“n”？只有这个for循环的最后一块，
				// 除非流控制令牌低？现在，永远。
				// 如果我们改变这一点，请参阅下面的评论。
				err = cc.bw.Flush()
			}
			cc.wmu.Unlock()
		}
		if err != nil {
			return err
		}
	}

	if sentEnd {
		// 已发送END_STREAM（这意味着我们没有
		// 预告片）并刷新，因为目前上面所有的
		// WriteData帧都会刷新。我们结束了。
		return nil
	}

	// 由于往返合同允许调用者在响应主体关闭后“变异或重用”
	// 请求，请验证这在访问拖车之前没有发生。
	cc.mu.Lock()
	trailer := req.Trailer
	err = cs.abortErr
	cc.mu.Unlock()
	if err != nil {
		return err
	}

	cc.wmu.Lock()
	defer cc.wmu.Unlock()
	var trls []byte
	if len(trailer) > 0 {
		trls, err = cc.encodeTrailers(trailer)
		if err != nil {
			return err
		}
	}

	// 发送END_流的两种方式：使用预告片或
	// 使用空数据帧。
	if len(trls) > 0 {
		err = cc.writeHeaders(cs.ID, true, maxFrameSize, trls)
	} else {
		err = cc.fr.WriteData(cs.ID, true, nil)
	}
	if ferr := cc.bw.Flush(); ferr != nil && err == nil {
		err = ferr
	}
	return err
}

// 等待FlowControl等待[1，min（maxBytes，cc.cs.maxFrameSize）]流
// 控制来自服务器的令牌。
// 如果流已死亡，则返回非零的令牌数或错误
// 。
func (cs *http2clientStream) awaitFlowControl(maxBytes int) (taken int32, err error) {
	cc := cs.cc
	ctx := cs.ctx
	cc.mu.Lock()
	defer cc.mu.Unlock()
	for {
		if cc.closed {
			return 0, http2errClientConnClosed
		}
		if cs.reqBodyClosed {
			return 0, http2errStopReqBodyWrite
		}
		select {
		case <-cs.abort:
			return 0, cs.abortErr
		case <-ctx.Done():
			return 0, ctx.Err()
		case <-cs.reqCancel:
			return 0, http2errRequestCanceled
		default:
		}
		if a := cs.flow.available(); a > 0 {
			take := a
			if int(take) > maxBytes {

				take = int32(maxBytes) // 不能截断int；take是int32 
			}
			if take > int32(cc.maxFrameSize) {
				take = int32(cc.maxFrameSize)
			}
			cs.flow.take(take)
			return take, nil
		}
		cc.cond.Wait()
	}
}

var http2errNilRequestURL = errors.New("http2: Request.URI is nil")

// 需要抄送。wmu将被拘留。
func (cc *http2ClientConn) encodeHeaders(req *Request, addGzipHeader bool, trailers string, contentLength int64) ([]byte, error) {
	cc.hbuf.Reset()
	if req.URL == nil {
		return nil, http2errNilRequestURL
	}

	host := req.Host
	if host == "" {
		host = req.URL.Host
	}
	host, err := httpguts.PunycodeHostPort(host)
	if err != nil {
		return nil, err
	}

	var path string
	if req.Method != "CONNECT" {
		path = req.URL.RequestURI()
		if !http2validPseudoPath(path) {
			orig := path
			path = strings.TrimPrefix(path, req.URL.Scheme+":// “+主机）
			if !http2validPseudoPath(path) {
				if req.URL.Opaque != "" {
					return nil, fmt.Errorf("invalid request :path %q from URL.Opaque = %q", orig, req.URL.Opaque)
				} else {
					return nil, fmt.Errorf("invalid request :path %q", orig)
				}
			}
		}
	}

	// 检查任何无效的头并返回错误，然后我们
	// 可能会污染我们的hpack状态。（我们希望能够
	// 继续为将来的请求重新使用hpack编码器）
	for k, vv := range req.Header {
		if !httpguts.ValidHeaderFieldName(k) {
			return nil, fmt.Errorf("invalid HTTP header name %q", k)
		}
		for _, v := range vv {
			if !httpguts.ValidHeaderFieldValue(v) {
				return nil, fmt.Errorf("invalid HTTP header value %q for header %q", v, k)
			}
		}
	}

	enumerateHeaders := func(f func(name, value string)) {
		// 8.1.2.3请求伪头字段
		// 路径伪头字段包括
		// 目标URI的路径和查询部分（路径绝对生成和可选的“？”字符
		// 后跟查询生成（见
		// /[RFC3986]第3.3和3.4节）。
		f(":authority", host)
		m := req.Method
		if m == "" {
			m = MethodGet
		}
		f(":method", m)
		if req.Method != "CONNECT" {
			f(":path", path)
			f(":scheme", req.URL.Scheme)
		}
		if trailers != "" {
			f("trailer", trailers)
		}

		var didUA bool
		for k, vv := range req.Header {
			if http2asciiEqualFold(k, "host") || http2asciiEqualFold(k, "content-length") {
				// 主机为：权威，已发送。
				// 内容长度是自动的，设置如下。
				continue
			} else if http2asciiEqualFold(k, "connection") ||
				http2asciiEqualFold(k, "proxy-connection") ||
				http2asciiEqualFold(k, "transfer-encoding") ||
				http2asciiEqualFold(k, "upgrade") ||
				http2asciiEqualFold(k, "keep-alive") {
				// 根据8.1.2.2特定于连接的头
				// 字段，不发送特定于连接的
				// 字段。我们已经检查了
				// 是否有错误，所以忽略其余部分。
				continue
			} else if http2asciiEqualFold(k, "user-agent") {
				// 匹配Go的http1行为：最多一个
				// 用户代理。如果设置为nil或空字符串，则
				// 然后忽略它。否则，如果未提及，
				// 包括默认值（如下）。
				didUA = true
				if len(vv) < 1 {
					continue
				}
				vv = vv[:1]
				if vv[0] == "" {
					continue
				}
			} else if http2asciiEqualFold(k, "cookie") {
				// 根据8.1.2.5，为了提高压缩效率，可以将
				// Cookie头字段拆分为单独的头字段，
				// 每个都有一个或多个Cookie对。
				for _, v := range vv {
					for {
						p := strings.IndexByte(v, ';')
						if p < 0 {
							break
						}
						f("cookie", v[:p])
						p++
						// 如果有分号，请在分号后面加空格。
						for p+1 <= len(v) && v[p] == ' ' {
							p++
						}
						v = v[p:]
					}
					if len(v) > 0 {
						f("cookie", v)
					}
				}
				continue
			}

			for _, v := range vv {
				f(k, v)
			}
		}
		if http2shouldSendReqContentLength(req.Method, contentLength) {
			f("content-length", strconv.FormatInt(contentLength, 10))
		}
		if addGzipHeader {
			f("accept-encoding", "gzip")
		}
		if !didUA {
			f("user-agent", http2defaultUserAgent)
		}
	}

	// 首先对报头进行字节计数，以确保
	// 我们不会超过cc。peerMaxHeaderListSize。这是在对报头进行编码之前作为一个单独的过程来完成的，以防止修改hpack状态。
	hlSize := uint64(0)
	enumerateHeaders(func(name, value string) {
		hf := hpack.HeaderField{Name: name, Value: value}
		hlSize += uint64(hf.Size())
	})

	if hlSize > cc.peerMaxHeaderListSize {
		return nil, http2errRequestHeaderListSize
	}

	trace := httptrace.ContextClientTrace(req.Context())
	traceHeaders := http2traceHasWroteHeaderField(trace)

	// 标题列表大小正常。写标题。
	enumerateHeaders(func(name, value string) {
		name, ascii := http2asciiToLower(name)
		if !ascii {
			// 跳过写入无效的头。根据RFC 7540第8.1.2节，标题
			// 字段名必须是ASCII字符（就像在HTTP/1.x中一样）。
			return
		}
		cc.writeHeader(name, value)
		if traceHeaders {
			http2traceWroteHeaderField(trace, name, value)
		}
	})

	return cc.hbuf.Bytes(), nil
}

// shouldSendReqContentLength报告http2是否。传输应发送
// 一个“内容长度”请求头。此逻辑基本上是net/http-
// transferWriter的副本。应该发送内容长度。
// contentLength是正确的contentLength（因此0表示实际上为0，并非未知）。
// /-1表示未知。
func http2shouldSendReqContentLength(method string, contentLength int64) bool {
	if contentLength > 0 {
		return true
	}
	if contentLength < 0 {
		return false
	}
	// 对于零正文，我们是否发送内容长度取决于方法。
	// 这对http2来说也没什么关系，不管是用END_流。
	switch method {
	case "POST", "PUT", "PATCH":
		return true
	default:
		return false
	}
}

// 需要抄送。wmu将被拘留。
func (cc *http2ClientConn) encodeTrailers(trailer Header) ([]byte, error) {
	cc.hbuf.Reset()

	hlSize := uint64(0)
	for k, vv := range trailer {
		for _, v := range vv {
			hf := hpack.HeaderField{Name: k, Value: v}
			hlSize += uint64(hf.Size())
		}
	}
	if hlSize > cc.peerMaxHeaderListSize {
		return nil, http2errRequestHeaderListSize
	}

	for k, vv := range trailer {
		lowKey, ascii := http2asciiToLower(k)
		if !ascii {
			// 跳过写入无效的标题。根据RFC 7540第8.1.2节，标题
			// 字段名必须是ASCII字符（就像在HTTP/1.x中一样）。
			continue
		}
		// 传输编码等。。已在
		// 开始往返
		for _, v := range vv {
			cc.writeHeader(lowKey, v)
		}
	}
	return cc.hbuf.Bytes(), nil
}

func (cc *http2ClientConn) writeHeader(name, value string) {
	if http2VerboseLogs {
		log.Printf("http2: Transport encoding header %q = %q", name, value)
	}
	cc.henc.WriteField(hpack.HeaderField{Name: name, Value: value})
}

type http2resAndError struct {
	_   http2incomparable
	res *Response
	err error
}

// 处进行筛选，需要抄送。我将被拘留。
func (cc *http2ClientConn) addStreamLocked(cs *http2clientStream) {
	cs.flow.add(int32(cc.initialWindowSize))
	cs.flow.setConnFlow(&cc.flow)
	cs.inflow.add(http2transportDefaultStreamFlow)
	cs.inflow.setConnFlow(&cc.inflow)
	cs.ID = cc.nextStreamID
	cc.nextStreamID += 2
	cc.streams[cs.ID] = cs
	if cs.ID == 0 {
		panic("assigned stream ID 0")
	}
}

func (cc *http2ClientConn) forgetStreamID(id uint32) {
	cc.mu.Lock()
	slen := len(cc.streams)
	delete(cc.streams, id)
	if len(cc.streams) != slen-1 {
		panic("forgetting unknown stream id")
	}
	cc.lastActive = time.Now()
	if len(cc.streams) == 0 && cc.idleTimer != nil {
		cc.idleTimer.Reset(cc.idleTimeout)
		cc.lastIdle = time.Now()
	}
	// 通过clientStream唤醒WriterRequestBody。等待FlowControl和
	// 如果有未决请求，请唤醒往返。
	cc.cond.Broadcast()

	closeOnIdle := cc.singleUse || cc.doNotReuse || cc.t.disableKeepAlives()
	if closeOnIdle && cc.streamsReserved == 0 && len(cc.streams) == 0 {
		if http2VerboseLogs {
			cc.vlogf("http2: Transport closing idle conn %p (forSingleUse=%v, maxStream=%v)", cc, cc.singleUse, cc.nextStreamID-2)
		}
		cc.closed = true
		defer cc.tconn.Close()
	}

	cc.mu.Unlock()
}

// clientConnReadLoop是clientConn的帧读取readLoop所拥有的国家。
type http2clientConnReadLoop struct {
	_  http2incomparable
	cc *http2ClientConn
}

// readLoop在自己的goroutine中运行，读取和分派帧。
func (cc *http2ClientConn) readLoop() {
	rl := &http2clientConnReadLoop{cc: cc}
	defer rl.cleanup()
	cc.readerErr = rl.run()
	if ce, ok := cc.readerErr.(http2ConnectionError); ok {
		cc.wmu.Lock()
		cc.fr.WriteGoAway(0, http2ErrCode(ce), nil)
		cc.wmu.Unlock()
	}
}

// 发送GOAWAY帧后，当服务器关闭
// TCP连接时，传输返回GOAWAY错误。
type http2GoAwayError struct {
	LastStreamID uint32
	ErrCode      http2ErrCode
	DebugData    string
}

func (e http2GoAwayError) Error() string {
	return fmt.Sprintf("http2: server sent GOAWAY and closed the connection; LastStreamID=%v, ErrCode=%v, debug=%q",
		e.LastStreamID, e.ErrCode, e.DebugData)
}

func http2isEOFOrNetReadError(err error) bool {
	if err == io.EOF {
		return true
	}
	ne, ok := err.(*net.OpError)
	return ok && ne.Op == "read"
}

func (rl *http2clientConnReadLoop) cleanup() {
	cc := rl.cc
	defer cc.tconn.Close()
	defer cc.t.connPool().MarkDead(cc)
	defer close(cc.readerDone)

	if cc.idleTimer != nil {
		cc.idleTimer.Stop()
	}

	// 如果服务器过早关闭，请关闭所有响应主体。
	// TODO:如果我们已经写了标题，但没有得到回复，也可以这样做。
	err := cc.readerErr
	cc.mu.Lock()
	if cc.goAway != nil && http2isEOFOrNetReadError(err) {
		err = http2GoAwayError{
			LastStreamID: cc.goAway.LastStreamID,
			ErrCode:      cc.goAway.ErrCode,
			DebugData:    cc.goAwayDebug,
		}
	} else if err == io.EOF {
		err = io.ErrUnexpectedEOF
	}
	cc.closed = true
	for _, cs := range cc.streams {
		select {
		case <-cs.peerClosed:
			// 服务器在关闭连接之前关闭了流，
			// 因此无需中断。
		default:
			cs.abortStreamLocked(err)
		}
	}
	cc.cond.Broadcast()
	cc.mu.Unlock()
}

// countReadFrameError调用传输。用字符串
// 表示错误的计数器错误。
func (cc *http2ClientConn) countReadFrameError(err error) {
	f := cc.t.CountError
	if f == nil || err == nil {
		return
	}
	if ce, ok := err.(http2ConnectionError); ok {
		errCode := http2ErrCode(ce)
		f(fmt.Sprintf("read_frame_conn_error_%s", errCode.stringToken()))
		return
	}
	if errors.Is(err, io.EOF) {
		f("read_frame_eof")
		return
	}
	if errors.Is(err, io.ErrUnexpectedEOF) {
		f("read_frame_unexpected_eof")
		return
	}
	if errors.Is(err, http2ErrFrameTooLarge) {
		f("read_frame_too_large")
		return
	}
	f("read_frame_other")
}

func (rl *http2clientConnReadLoop) run() error {
	cc := rl.cc
	gotSettings := false
	readIdleTimeout := cc.t.ReadIdleTimeout
	var t *time.Timer
	if readIdleTimeout != 0 {
		t = time.AfterFunc(readIdleTimeout, cc.healthCheck)
		defer t.Stop()
	}
	for {
		f, err := cc.fr.ReadFrame()
		if t != nil {
			t.Reset(readIdleTimeout)
		}
		if err != nil {
			cc.vlogf("http2: Transport readFrame error on conn %p: (%T) %v", cc, err, err)
		}
		if se, ok := err.(http2StreamError); ok {
			if cs := rl.streamByID(se.StreamID); cs != nil {
				if se.Cause == nil {
					se.Cause = cc.fr.errDetail
				}
				rl.endStreamError(cs, se)
			}
			continue
		} else if err != nil {
			cc.countReadFrameError(err)
			return err
		}
		if http2VerboseLogs {
			cc.vlogf("http2: Transport received %s", http2summarizeFrame(f))
		}
		if !gotSettings {
			if _, ok := f.(*http2SettingsFrame); !ok {
				cc.logf("protocol error: received %T before a SETTINGS frame", f)
				return http2ConnectionError(http2ErrCodeProtocol)
			}
			gotSettings = true
		}

		switch f := f.(type) {
		case *http2MetaHeadersFrame:
			err = rl.processHeaders(f)
		case *http2DataFrame:
			err = rl.processData(f)
		case *http2GoAwayFrame:
			err = rl.processGoAway(f)
		case *http2RSTStreamFrame:
			err = rl.processResetStream(f)
		case *http2SettingsFrame:
			err = rl.processSettings(f)
		case *http2PushPromiseFrame:
			err = rl.processPushPromise(f)
		case *http2WindowUpdateFrame:
			err = rl.processWindowUpdate(f)
		case *http2PingFrame:
			err = rl.processPing(f)
		default:
			cc.logf("Transport: unhandled response frame type %T", f)
		}
		if err != nil {
			if http2VerboseLogs {
				cc.vlogf("http2: Transport conn %p received error from processing frame %v: %v", cc, http2summarizeFrame(f), err)
			}
			return err
		}
	}
}

func (rl *http2clientConnReadLoop) processHeaders(f *http2MetaHeadersFrame) error {
	cs := rl.streamByID(f.StreamID)
	if cs == nil {
		// 如果我们在
		// 服务器的响应仍在运行时取消了一个请求，我们就会到达这里。所以如果这个
		// 只是我们取消的东西，忽略它。
		return nil
	}
	if cs.readClosed {
		rl.endStreamError(cs, http2StreamError{
			StreamID: f.StreamID,
			Code:     http2ErrCodeProtocol,
			Cause:    errors.New("protocol error: headers after END_STREAM"),
		})
		return nil
	}
	if !cs.firstByte {
		if cs.trace != nil {
			// TODO（bradfitz）：在我们第一次读取9字节的头时，将第一个响应字节提前移动，而不是等待
			// ，直到所有头+连续帧都被合并。这个暂时有效。
			http2traceFirstResponseByte(cs.trace)
		}
		cs.firstByte = true
	}
	if !cs.pastHeaders {
		cs.pastHeaders = true
	} else {
		return rl.processTrailers(cs, f)
	}

	res, err := rl.handleResponse(cs, f)
	if err != nil {
		if _, ok := err.(http2ConnectionError); ok {
			return err
		}
		// 任何其他错误类型都是流错误。
		rl.endStreamError(cs, http2StreamError{
			StreamID: f.StreamID,
			Code:     http2ErrCodeProtocol,
			Cause:    err,
		})
		return nil // 从进程中返回nil*函数以保持conn活动
	}
	if res == nil {
		// （nil，nil）特殊情况。参见HandlerResponse文档。
		return nil
	}
	cs.resTrailer = &res.Trailer
	cs.res = res
	close(cs.respHeaderRecv)
	if f.StreamEnded() {
		rl.endStream(cs)
	}
	return nil
}

// 可能返回错误类型nil或ConnectionError。任何其他错误值
// 都是ErrCodeProtocol类型的流错误。在这种情况下返回的错误是
// 详细信息。
// 
// 作为特例，HandlerResponse可以返回（nil，nil）跳过
// 帧（目前仅用于1xx响应）。
func (rl *http2clientConnReadLoop) handleResponse(cs *http2clientStream, f *http2MetaHeadersFrame) (*Response, error) {
	if f.Truncated {
		return nil, http2errResponseHeaderListSize
	}

	status := f.PseudoValue("status")
	if status == "" {
		return nil, errors.New("malformed response from server: missing status pseudo header")
	}
	statusCode, err := strconv.Atoi(status)
	if err != nil {
		return nil, errors.New("malformed response from server: malformed non-numeric status pseudo header")
	}

	regularFields := f.RegularFields()
	strs := make([]string, len(regularFields))
	header := make(Header, len(regularFields))
	res := &Response{
		Proto:      "HTTP/2.0",
		ProtoMajor: 2,
		Header:     header,
		StatusCode: statusCode,
		Status:     status + " " + StatusText(statusCode),
	}
	for _, hf := range regularFields {
		key := CanonicalHeaderKey(hf.Name)
		if key == "Trailer" {
			t := res.Trailer
			if t == nil {
				t = make(Header)
				res.Trailer = t
			}
			http2foreachHeaderElement(hf.Value, func(v string) {
				t[CanonicalHeaderKey(v)] = nil
			})
		} else {
			vv := header[key]
			if vv == nil && len(strs) > 0 {
				// 这很可能是一个单元素键。
				// 大多数头不是多值的。
				// 将strs[0]上的容量设置为1，这样以后的任何追加
				// 都不会将切片扩展到其他字符串中。
				vv, strs = strs[:1:1], strs[1:]
				vv[0] = hf.Value
				header[key] = vv
			} else {
				header[key] = append(vv, hf.Value)
			}
		}
	}

	if statusCode >= 100 && statusCode <= 199 {
		if f.StreamEnded() {
			return nil, errors.New("1xx informational response with END_STREAM flag")
		}
		cs.num1xx++
		const max1xxResponses = 5 // 任意绑定信息响应的数量，与net/http 
		if cs.num1xx > max1xxResponses {
			return nil, errors.New("http2: too many 1xx informational responses")
		}
		if fn := cs.get1xxTraceFunc(); fn != nil {
			if err := fn(statusCode, textproto.MIMEHeader(header)); err != nil {
				return nil, err
			}
		}
		if statusCode == 100 {
			http2traceGot100Continue(cs.trace)
			select {
			case cs.on100 <- struct{}{}:
			default:
			}
		}
		cs.pastHeaders = false // 重做
		return nil, nil
	}

	res.ContentLength = -1
	if clens := res.Header["Content-Length"]; len(clens) == 1 {
		if cl, err := strconv.ParseUint(clens[0], 10, 63); err == nil {
			res.ContentLength = int64(cl)
		} else {
			// TODO:care？与http/1不同，它不会扰乱我们的框架，因此
			// 忽略它更安全。
		}
	} else if len(clens) > 1 {
		// TODO:关心吗？与http/1不同，它不会扰乱我们的框架，因此
		// 忽略它更安全。
	} else if f.StreamEnded() && !cs.isHead {
		res.ContentLength = 0
	}

	if cs.isHead {
		res.Body = http2noBody
		return res, nil
	}

	if f.StreamEnded() {
		if res.ContentLength > 0 {
			res.Body = http2missingBody{}
		} else {
			res.Body = http2noBody
		}
		return res, nil
	}

	cs.bufPipe.setBuffer(&http2dataBuffer{expected: res.ContentLength})
	cs.bytesRemain = res.ContentLength
	res.Body = http2transportResponseBody{cs}

	if cs.requestedGzip && http2asciiEqualFold(res.Header.Get("Content-Encoding"), "gzip") {
		res.Header.Del("Content-Encoding")
		res.Header.Del("Content-Length")
		res.ContentLength = -1
		res.Body = &http2gzipReader{body: res.Body}
		res.Uncompressed = true
	}
	return res, nil
}

func (rl *http2clientConnReadLoop) processTrailers(cs *http2clientStream, f *http2MetaHeadersFrame) error {
	if cs.pastTrailers {
		// 此流的头帧太多。
		return http2ConnectionError(http2ErrCodeProtocol)
	}
	cs.pastTrailers = true
	if !f.StreamEnded() {
		// 我们希望拖车的任何头文件也有END_流。
		return http2ConnectionError(http2ErrCodeProtocol)
	}
	if len(f.PseudoFields()) > 0 {
		// 没有为拖车定义伪头字段。
		// TODO:ConnectionError可能过于苛刻了？检查
		return http2ConnectionError(http2ErrCodeProtocol)
	}

	trailer := make(Header)
	for _, hf := range f.RegularFields() {
		key := CanonicalHeaderKey(hf.Name)
		trailer[key] = append(trailer[key], hf.Value)
	}
	cs.trailer = trailer

	rl.endStream(cs)
	return nil
}

// transportResponseBody是具体的运输类型。往返
// 回复。身体这是一个io。读近一点。
type http2transportResponseBody struct {
	cs *http2clientStream
}

func (b http2transportResponseBody) Read(p []byte) (n int, err error) {
	cs := b.cs
	cc := cs.cc

	if cs.readErr != nil {
		return 0, cs.readErr
	}
	n, err = b.cs.bufPipe.Read(p)
	if cs.bytesRemain != -1 {
		if int64(n) > cs.bytesRemain {
			n = int(cs.bytesRemain)
			if err == nil {
				err = errors.New("net/http: server replied with more than declared Content-Length; truncated")
				cs.abortStream(err)
			}
			cs.readErr = err
			return int(cs.bytesRemain), err
		}
		cs.bytesRemain -= int64(n)
		if err == io.EOF && cs.bytesRemain > 0 {
			err = io.ErrUnexpectedEOF
			cs.readErr = err
			return n, err
		}
	}
	if n == 0 {
		// 没有要发回的流控制令牌。
		return
	}

	cc.mu.Lock()
	var connAdd, streamAdd int32
	// 先检查连接电平，再检查流电平。
	if v := cc.inflow.available(); v < http2transportDefaultConnFlow/2 {
		connAdd = http2transportDefaultConnFlow - v
		cc.inflow.add(connAdd)
	}
	if err == nil { // 如果流结束或失败，则无需刷新。ABCFDG 
		v := int(cs.inflow.available()) + cs.bufPipe.Len()
		if v < http2transportDefaultStreamFlow-http2transportDefaultStreamMinRefresh {
			streamAdd = int32(http2transportDefaultStreamFlow - v)
			cs.inflow.add(streamAdd)
		}
	}
	cc.mu.Unlock()

	if connAdd != 0 || streamAdd != 0 {
		cc.wmu.Lock()
		defer cc.wmu.Unlock()
		if connAdd != 0 {
			cc.fr.WriteWindowUpdate(0, http2mustUint31(connAdd))
		}
		if streamAdd != 0 {
			cc.fr.WriteWindowUpdate(cs.ID, http2mustUint31(streamAdd))
		}
		cc.bw.Flush()
	}
	return
}

var http2errClosedResponseBody = errors.New("http2: response body closed")

func (b http2transportResponseBody) Close() error {
	cs := b.cs
	cc := cs.cc

	unread := cs.bufPipe.Len()
	if unread > 0 {
		cc.mu.Lock()
		// 返回连接级别流量控制。
		if unread > 0 {
			cc.inflow.add(int32(unread))
		}
		cc.mu.Unlock()

		// TODO（dneil）：获取此互斥可以无限期阻止。
		// 移动流控制返回goroutine？
		cc.wmu.Lock()
		// 返回连接级别流量控制。
		if unread > 0 {
			cc.fr.WriteWindowUpdate(0, uint32(unread))
		}
		cc.bw.Flush()
		cc.wmu.Unlock()
	}

	cs.bufPipe.BreakWithError(http2errClosedResponseBody)
	cs.abortStream(http2errClosedResponseBody)

	select {
	case <-cs.donec:
	case <-cs.ctx.Done():
		// 请参阅golang/go#49366:net/http包可以在完全读取响应正文后取消
		// 请求上下文。
		// 不要将此视为错误。
		return nil
	case <-cs.reqCancel:
		return http2errRequestCanceled
	}
	return nil
}

func (rl *http2clientConnReadLoop) processData(f *http2DataFrame) error {
	cc := rl.cc
	cs := rl.streamByID(f.StreamID)
	data := f.Data()
	if cs == nil {
		cc.mu.Lock()
		neverSent := cc.nextStreamID
		cc.mu.Unlock()
		if f.StreamID >= neverSent {
			// 我们从未要求过这个。
			cc.logf("http2: Transport received unsolicited DATA frame; closing connection")
			return http2ConnectionError(http2ErrCodeProtocol)
		}
		// 我们可能确实要求过，但取消了。别理它。
		// TODO:这里要更严格吗？只是默默地忽略我们取消的事情，而不是被同伴正常关闭的事情？不积累太多的状态。

		// 但至少返回其流控制：
		if f.Length > 0 {
			cc.mu.Lock()
			cc.inflow.add(int32(f.Length))
			cc.mu.Unlock()

			cc.wmu.Lock()
			cc.fr.WriteWindowUpdate(0, uint32(f.Length))
			cc.bw.Flush()
			cc.wmu.Unlock()
		}
		return nil
	}
	if cs.readClosed {
		cc.logf("protocol error: received DATA after END_STREAM")
		rl.endStreamError(cs, http2StreamError{
			StreamID: f.StreamID,
			Code:     http2ErrCodeProtocol,
		})
		return nil
	}
	if !cs.firstByte {
		cc.logf("protocol error: received DATA before a HEADERS frame")
		rl.endStreamError(cs, http2StreamError{
			StreamID: f.StreamID,
			Code:     http2ErrCodeProtocol,
		})
		return nil
	}
	if f.Length > 0 {
		if cs.isHead && len(data) > 0 {
			cc.logf("protocol error: received DATA on a HEAD request")
			rl.endStreamError(cs, http2StreamError{
				StreamID: f.StreamID,
				Code:     http2ErrCodeProtocol,
			})
			return nil
		}
		// 检查连接级别流控制。
		cc.mu.Lock()
		if cs.inflow.available() >= int32(f.Length) {
			cs.inflow.take(int32(f.Length))
		} else {
			cc.mu.Unlock()
			return http2ConnectionError(http2ErrCodeFlowControl)
		}
		// 现在返回任何填充的流控制，因为我们不会在以后的正文阅读中退款。
		var refund int
		if pad := int(f.Length) - len(data); pad > 0 {
			refund += pad
		}

		didReset := false
		var err error
		if len(data) > 0 {
			if _, err = cs.bufPipe.Write(data); err != nil {
				// 现在返回len（数据）如果流已经关闭，
				// 因为数据永远不会被读取。gong zuo jian defg
				didReset = true
				refund += len(data)
			}
		}

		if refund > 0 {
			cc.inflow.add(int32(refund))
			if !didReset {
				cs.inflow.add(int32(refund))
			}
		}
		cc.mu.Unlock()

		if refund > 0 {
			cc.wmu.Lock()
			cc.fr.WriteWindowUpdate(0, uint32(refund))
			if !didReset {
				cc.fr.WriteWindowUpdate(cs.ID, uint32(refund))
			}
			cc.bw.Flush()
			cc.wmu.Unlock()
		}

		if err != nil {
			rl.endStreamError(cs, err)
			return nil
		}
	}

	if f.StreamEnded() {
		rl.endStream(cs)
	}
	return nil
}

func (rl *http2clientConnReadLoop) endStream(cs *http2clientStream) {
	if !cs.readClosed {
		cs.readClosed = true
		// 关闭cs。bufPipe和cs。用cc关闭。mu保持以避免
		// 竞争条件：调用方可以读取io。来自响应的EOF。身体
		// 在我们关闭cs之前关闭尸体。peerClosed，导致
		// cleanupWriteRequest发送RST_流。
		rl.cc.mu.Lock()
		defer rl.cc.mu.Unlock()
		cs.bufPipe.closeWithErrorAndCode(io.EOF, cs.copyTrailers)
		close(cs.peerClosed)
	}
}

func (rl *http2clientConnReadLoop) endStreamError(cs *http2clientStream, err error) {
	cs.readAborted = true
	cs.abortStream(err)
}

func (rl *http2clientConnReadLoop) streamByID(id uint32) *http2clientStream {
	rl.cc.mu.Lock()
	defer rl.cc.mu.Unlock()
	cs := rl.cc.streams[id]
	if cs != nil && !cs.readAborted {
		return cs
	}
	return nil
}

func (cs *http2clientStream) copyTrailers() {
	for k, vv := range cs.trailer {
		t := cs.resTrailer
		if *t == nil {
			*t = make(Header)
		}
		(*t)[k] = vv
	}
}

func (rl *http2clientConnReadLoop) processGoAway(f *http2GoAwayFrame) error {
	cc := rl.cc
	cc.t.connPool().MarkDead(cc)
	if f.ErrCode != 0 {
		// 待办事项：处理更多的问题。特别是错误代码
		cc.vlogf("transport got GOAWAY with error code = %v", f.ErrCode)
		if fn := cc.t.CountError; fn != nil {
			fn("recv_goaway_" + f.ErrCode.stringToken())
		}

	}
	cc.setGoAway(f)
	return nil
}

func (rl *http2clientConnReadLoop) processSettings(f *http2SettingsFrame) error {
	cc := rl.cc
	// 在这里同时锁定mu和wmu允许帧编码读取设置，只保留wmu。
	// 在不需要f.IsAck（）的情况下获取wmu，但很方便，而且基本无害。
	cc.wmu.Lock()
	defer cc.wmu.Unlock()

	if err := rl.processSettingsNoWrite(f); err != nil {
		return err
	}
	if !f.IsAck() {
		cc.fr.WriteSettingsAck()
		cc.bw.Flush()
	}
	return nil
}

func (rl *http2clientConnReadLoop) processSettingsNoWrite(f *http2SettingsFrame) error {
	cc := rl.cc
	cc.mu.Lock()
	defer cc.mu.Unlock()

	if f.IsAck() {
		if cc.wantSettingsAck {
			cc.wantSettingsAck = false
			return nil
		}
		return http2ConnectionError(http2ErrCodeProtocol)
	}

	var seenMaxConcurrentStreams bool
	err := f.ForeachSetting(func(s http2Setting) error {
		switch s.ID {
		case http2SettingMaxFrameSize:
			cc.maxFrameSize = s.Val
		case http2SettingMaxConcurrentStreams:
			cc.maxConcurrentStreams = s.Val
			seenMaxConcurrentStreams = true
		case http2SettingMaxHeaderListSize:
			cc.peerMaxHeaderListSize = uint64(s.Val)
		case http2SettingInitialWindowSize:
			// 超过最大流量控制的值
			// 窗口大小为2^31-1时，必须视为
			// 连接错误（第5.4.1节），类型为
			// 流量控制错误。
			if s.Val > math.MaxInt32 {
				return http2ConnectionError(http2ErrCodeFlowControl)
			}

			// 根据旧的初始
			// 帧的流量控制。
			// 窗口大小和此窗口大小的差异，调整当前打开的
			delta := int32(s.Val) - int32(cc.initialWindowSize)
			for _, cs := range cc.streams {
				cs.flow.add(delta)
			}
			cc.cond.Broadcast()

			cc.initialWindowSize = s.Val
		default:
			// TODO（bradfitz）：处理更多设置？设置\u标题\u表格\u大小。
			cc.vlogf("Unhandled Setting: %v", s)
		}
		return nil
	})
	if err != nil {
		return err
	}

	if !cc.seenSettings {
		if !seenMaxConcurrentStreams {
			// 这是服务器初始设置框架，它不包含MAX_CONCURRENT_STREAMS字段，因此
			// 将此
			// 连接可以建立的并发流的数量增加到默认值。
			cc.maxConcurrentStreams = http2defaultMaxConcurrentStreams
		}
		cc.seenSettings = true
	}

	return nil
}

func (rl *http2clientConnReadLoop) processWindowUpdate(f *http2WindowUpdateFrame) error {
	cc := rl.cc
	cs := rl.streamByID(f.StreamID)
	if f.StreamID != 0 && cs == nil {
		return nil
	}

	cc.mu.Lock()
	defer cc.mu.Unlock()

	fl := &cc.flow
	if cs != nil {
		fl = &cs.flow
	}
	if !fl.add(int32(f.Increment)) {
		return http2ConnectionError(http2ErrCodeFlowControl)
	}
	cc.cond.Broadcast()
	return nil
}

func (rl *http2clientConnReadLoop) processResetStream(f *http2RSTStreamFrame) error {
	cs := rl.streamByID(f.StreamID)
	if cs == nil {
		// TODO:如果服务器试图重新设置空闲流，则返回错误
		return nil
	}
	serr := http2streamError(cs.ID, f.ErrCode)
	serr.Cause = http2errFromPeer
	if f.ErrCode == http2ErrCodeProtocol {
		rl.cc.SetDoNotReuse()
	}
	if fn := cs.cc.t.CountError; fn != nil {
		fn("recv_rststream_" + f.ErrCode.stringToken())
	}
	cs.abortStream(serr)

	cs.bufPipe.CloseWithError(serr)
	return nil
}

// Ping向服务器发送Ping帧并等待确认。
func (cc *http2ClientConn) Ping(ctx context.Context) error {
	c := make(chan struct{})
	// 生成一个随机有效负载
	var p [8]byte
	for {
		if _, err := rand.Read(p[:]); err != nil {
			return err
		}
		cc.mu.Lock()
		// 插入前检查dup 
		if _, found := cc.pings[p]; !found {
			cc.pings[p] = c
			cc.mu.Unlock()
			break
		}
		cc.mu.Unlock()
	}
	errc := make(chan error, 1)
	go func() {
		cc.wmu.Lock()
		defer cc.wmu.Unlock()
		if err := cc.fr.WritePing(false, p); err != nil {
			errc <- err
			return
		}
		if err := cc.bw.Flush(); err != nil {
			errc <- err
			return
		}
	}()
	select {
	case <-c:
		return nil
	case err := <-errc:
		return err
	case <-ctx.Done():
		return ctx.Err()
	case <-cc.readerDone:
		// 连接关闭
		return cc.readerErr
	}
}

func (rl *http2clientConnReadLoop) processPing(f *http2PingFrame) error {
	if f.IsAck() {
		cc := rl.cc
		cc.mu.Lock()
		defer cc.mu.Unlock()
		// 如果确认，通知侦听器如果有
		if c, ok := cc.pings[f.Data]; ok {
			close(c)
			delete(cc.pings, f.Data)
		}
		return nil
	}
	cc := rl.cc
	cc.wmu.Lock()
	defer cc.wmu.Unlock()
	if err := cc.fr.WritePing(true, f.Data); err != nil {
		return err
	}
	return cc.bw.Flush()
}

func (rl *http2clientConnReadLoop) processPushPromise(f *http2PushPromiseFrame) error {
	// 我们告诉对等方我们不需要它们。
	// 规范说明：
	// “如果对等端点的设置设置为0，则不得发送推送承诺。
	// 已设置此设置并已收到确认的端点必须
	// 将接收推送承诺帧视为连接
	// 错误（第5.4.1节）协议类型错误。“
	return http2ConnectionError(http2ErrCodeProtocol)
}

func (cc *http2ClientConn) writeStreamReset(streamID uint32, code http2ErrCode, err error) {
	// TODO:一旦
	// HTTP社区提出了一些错误代码，就将错误映射到更有趣的错误代码。但目前对于
	// RST_流，没有与GOAWAY frame的调试
	// 数据等效的错误代码，而且错误代码都非常模糊（“取消”）.
	cc.wmu.Lock()
	cc.fr.WriteRSTStream(streamID, code)
	cc.bw.Flush()
	cc.wmu.Unlock()
}

var (
	http2errResponseHeaderListSize = errors.New("http2: response header list larger than advertised limit")
	http2errRequestHeaderListSize  = errors.New("http2: request header list larger than peer's advertised limit")
)

func (cc *http2ClientConn) logf(format string, args ...interface{}) {
	cc.t.logf(format, args...)
}

func (cc *http2ClientConn) vlogf(format string, args ...interface{}) {
	cc.t.vlogf(format, args...)
}

func (t *http2Transport) vlogf(format string, args ...interface{}) {
	if http2VerboseLogs {
		t.logf(format, args...)
	}
}

func (t *http2Transport) logf(format string, args ...interface{}) {
	log.Printf(format, args...)
}

var http2noBody io.ReadCloser = ioutil.NopCloser(bytes.NewReader(nil))

type http2missingBody struct{}

func (http2missingBody) Close() error { return nil }

func (http2missingBody) Read([]byte) (int, error) { return 0, io.ErrUnexpectedEOF }

func http2strSliceContains(ss []string, s string) bool {
	for _, v := range ss {
		if v == s {
			return true
		}
	}
	return false
}

type http2erringRoundTripper struct{ err error }

func (rt http2erringRoundTripper) RoundTripErr() error { return rt.err }

func (rt http2erringRoundTripper) RoundTrip(*Request) (*Response, error) { return nil, rt.err }

// gzip阅读器包装了一个响应体，这样它就可以懒洋洋地调用gzip。NewReader在第一次呼叫中读取
type http2gzipReader struct {
	_    http2incomparable
	body io.ReadCloser // 基本响应。Body 
	zr   *gzip.Reader  // 延迟初始化的gzip读卡器
	zerr error         // 粘性错误
}

func (gz *http2gzipReader) Read(p []byte) (n int, err error) {
	if gz.zerr != nil {
		return 0, gz.zerr
	}
	if gz.zr == nil {
		gz.zr, err = gzip.NewReader(gz.body)
		if err != nil {
			gz.zerr = err
			return 0, err
		}
	}
	return gz.zr.Read(p)
}

func (gz *http2gzipReader) Close() error {
	return gz.body.Close()
}

type http2errorReader struct{ err error }

func (r http2errorReader) Read(p []byte) (int, error) { return 0, r.err }

// isConnectionCloseRequest报告req是否应使用自己的
// 连接进行单个请求，然后关闭连接。
func http2isConnectionCloseRequest(req *Request) bool {
	return req.Close || httpguts.HeaderValuesContainsToken(req.Header["Connection"], "close")
}

// RegisterHttpProtocol调用传输。注册协议但
// 将恐慌转化为错误。
func http2registerHTTPSProtocol(t *Transport, rt http2noDialH2RoundTripper) (err error) {
	defer func() {
		if e := recover(); e != nil {
			err = fmt.Errorf("%v", e)
		}
	}()
	t.RegisterProtocol("https", rt)
	return nil
}

// noDialH2RoundTripper是一个RoundTripper，它只会尝试完成请求
// 如果已经有到主机的缓存连接。
// （该字段已导出，因此可以通过反射从网络/http访问；已测试
// by TestNoDialH2RoundTripperType）
type http2noDialH2RoundTripper struct{ *http2Transport }

func (rt http2noDialH2RoundTripper) RoundTrip(req *Request) (*Response, error) {
	res, err := rt.http2Transport.RoundTrip(req)
	if http2isNoCachedConnError(err) {
		return nil, ErrSkipAltProtocol
	}
	return res, err
}

func (t *http2Transport) idleConnTimeout() time.Duration {
	if t.t1 != nil {
		return t.t1.IdleConnTimeout
	}
	return 0
}

func http2traceGetConn(req *Request, hostPort string) {
	trace := httptrace.ContextClientTrace(req.Context())
	if trace == nil || trace.GetConn == nil {
		return
	}
	trace.GetConn(hostPort)
}

func http2traceGotConn(req *Request, cc *http2ClientConn, reused bool) {
	trace := httptrace.ContextClientTrace(req.Context())
	if trace == nil || trace.GotConn == nil {
		return
	}
	ci := httptrace.GotConnInfo{Conn: cc.tconn}
	ci.Reused = reused
	cc.mu.Lock()
	ci.WasIdle = len(cc.streams) == 0 && reused
	if ci.WasIdle && !cc.lastActive.IsZero() {
		ci.IdleTime = time.Now().Sub(cc.lastActive)
	}
	cc.mu.Unlock()

	trace.GotConn(ci)
}

func http2traceWroteHeaders(trace *httptrace.ClientTrace) {
	if trace != nil && trace.WroteHeaders != nil {
		trace.WroteHeaders()
	}
}

func http2traceGot100Continue(trace *httptrace.ClientTrace) {
	if trace != nil && trace.Got100Continue != nil {
		trace.Got100Continue()
	}
}

func http2traceWait100Continue(trace *httptrace.ClientTrace) {
	if trace != nil && trace.Wait100Continue != nil {
		trace.Wait100Continue()
	}
}

func http2traceWroteRequest(trace *httptrace.ClientTrace, err error) {
	if trace != nil && trace.WroteRequest != nil {
		trace.WroteRequest(httptrace.WroteRequestInfo{Err: err})
	}
}

func http2traceFirstResponseByte(trace *httptrace.ClientTrace) {
	if trace != nil && trace.GotFirstResponseByte != nil {
		trace.GotFirstResponseByte()
	}
}

// writeFramer由用于写入帧的任何类型实现。
type http2writeFramer interface {
	writeFrame(http2writeContext) error

	// staysWithinBuffer报告作者是否承诺
	// 它将只写入小于或等于大小字节的数据，并且不会刷新写入上下文。
	staysWithinBuffer(size int) bool
}

// writeContext是各种框架编写器所需的接口
// 类型如下。以下所有WriteName方法都是通过
// 帧写入调度程序调度的（请参阅writeScheduler in WriteScheed.go）。
// 
// 此接口由*serverConn实现。
// 
// TODO:决定是否a）在客户端代码中使用此选项（它没有
// 最终使用此选项，因为它有一个更简单的设计，而不是
// 目前正在实现优先级），或者b）删除此选项并
// 使服务器代码更具体一些。
type http2writeContext interface {
	Framer() *http2Framer
	Flush() error
	CloseConn() error
	// HeaderEncoder返回一个HPACK编码器，该编码器写入
	// 返回的缓冲区。
	HeaderEncoder() (*hpack.Encoder, *bytes.Buffer)
}

// WriteEndStream报告w是否写入将转换
// 流到半封闭局部状态的帧。对于RST_流
// 返回false，这将关闭整个流（而不仅仅是本地的一半）。
func http2writeEndsStream(w http2writeFramer) bool {
	switch v := w.(type) {
	case *http2writeData:
		return v.endStream
	case *http2writeResHeaders:
		return v.endStream
	case nil:
		// 只有在w被故意禁用以防止使用后，调用方重新使用w时，才会发生这种情况。把这个
		// 放在这里，以捕捉未来的重构破坏它。
		panic("writeEndsStream called on nil writeFramer")
	}
	return false
}

type http2flushFrameWriter struct{}

func (http2flushFrameWriter) writeFrame(ctx http2writeContext) error {
	return ctx.Flush()
}

func (http2flushFrameWriter) staysWithinBuffer(max int) bool { return false }

type http2writeSettings []http2Setting

func (s http2writeSettings) staysWithinBuffer(max int) bool {
	const settingSize = 6 // uint16+uint32 
	return http2frameHeaderLen+settingSize*len(s) <= max

}

func (s http2writeSettings) writeFrame(ctx http2writeContext) error {
	return ctx.Framer().WriteSettings([]http2Setting(s)...)
}

type http2writeGoAway struct {
	maxStreamID uint32
	code        http2ErrCode
}

func (p *http2writeGoAway) writeFrame(ctx http2writeContext) error {
	err := ctx.Framer().WriteGoAway(p.maxStreamID, p.code, nil)
	ctx.Flush() // 忽略错误：我们正在挂断它们
	return err
}

func (*http2writeGoAway) staysWithinBuffer(max int) bool { return false } // 刷新

type http2writeData struct {
	streamID  uint32
	p         []byte
	endStream bool
}

func (w *http2writeData) String() string {
	return fmt.Sprintf("writeData(stream=%d, p=%d, endStream=%v)", w.streamID, len(w.p), w.endStream)
}

func (w *http2writeData) writeFrame(ctx http2writeContext) error {
	return ctx.Framer().WriteData(w.streamID, w.endStream, w.p)
}

func (w *http2writeData) staysWithinBuffer(max int) bool {
	return http2frameHeaderLen+len(w.p) <= max
}

// handlerPanicRST是当
// 处理程序恐慌时从处理程序goroutines发送的消息。
type http2handlerPanicRST struct {
	StreamID uint32
}

func (hp http2handlerPanicRST) writeFrame(ctx http2writeContext) error {
	return ctx.Framer().WriteRSTStream(hp.StreamID, http2ErrCodeInternal)
}

func (hp http2handlerPanicRST) staysWithinBuffer(max int) bool { return http2frameHeaderLen+4 <= max }

func (se http2StreamError) writeFrame(ctx http2writeContext) error {
	return ctx.Framer().WriteRSTStream(se.StreamID, se.Code)
}

func (se http2StreamError) staysWithinBuffer(max int) bool { return http2frameHeaderLen+4 <= max }

type http2writePingAck struct{ pf *http2PingFrame }

func (w http2writePingAck) writeFrame(ctx http2writeContext) error {
	return ctx.Framer().WritePing(true, w.pf.Data)
}

func (w http2writePingAck) staysWithinBuffer(max int) bool {
	return http2frameHeaderLen+len(w.pf.Data) <= max
}

type http2writeSettingsAck struct{}

func (http2writeSettingsAck) writeFrame(ctx http2writeContext) error {
	return ctx.Framer().WriteSettingsAck()
}

func (http2writeSettingsAck) staysWithinBuffer(max int) bool { return http2frameHeaderLen <= max }

// splitHeaderBlock将headerBlock拆分为多个片段，以便每个片段在单个帧中适合
// ，然后为每个片段调用fn。firstFrag/lastFrag分别为第一个/最后一个片段的正确
// 。
func http2splitHeaderBlock(ctx http2writeContext, headerBlock []byte, fn func(ctx http2writeContext, frag []byte, firstFrag, lastFrag bool) error) error {
	// 目前我们很懒惰，只需选择所有对等方必须支持的最小最大帧大小
	// 即可。后来我们可以关心
	// 更多，如果对方宣传的话，我们可以发送更大的帧，但是
	// 没有什么意义。大多数头都很小（所以我们通常不会有连续帧），额外的帧只会浪费9字节。
	const maxFrameSize = 16384

	first := true
	for len(headerBlock) > 0 {
		frag := headerBlock
		if len(frag) > maxFrameSize {
			frag = frag[:maxFrameSize]
		}
		headerBlock = headerBlock[len(frag):]
		if err := fn(ctx, frag, first, len(headerBlock) == 0); err != nil {
			return err
		}
		first = false
	}
	return nil
}

// writeResHeaders是一个请求，用于从服务器处理程序中写入HTTP响应头或尾文件的头文件和0+继续帧
// 。
type http2writeResHeaders struct {
	streamID    uint32
	httpResCode int      // 0表示否：状态“行
	h           Header   // 可能为零
	trailers    []string // 如果为非零，应写入h的哪些键。零意味着一切。
	endStream   bool

	date          string
	contentType   string
	contentLength string
}

func http2encKV(enc *hpack.Encoder, k, v string) {
	if http2VerboseLogs {
		log.Printf("http2: server encoding header %q = %q", k, v)
	}
	enc.WriteField(hpack.HeaderField{Name: k, Value: v})
}

func (w *http2writeResHeaders) staysWithinBuffer(max int) bool {
	// TODO:这是一个常见的问题。如果我们能聪明一点，计算出足够快的大小，或者至少是一个保守的，通常会触发的上限，那么在这里返回真正的
	// 并进入快速路径就好了。（也许如果w.h和
	// w.Trailes为零，那么我们不需要列举它。）
	// 否则，我担心仅仅计算长度到
	// 回答这个问题会比~2µs的好处慢。
	return false
}

func (w *http2writeResHeaders) writeFrame(ctx http2writeContext) error {
	enc, buf := ctx.HeaderEncoder()
	buf.Reset()

	if w.httpResCode != 0 {
		http2encKV(enc, ":status", http2httpCodeString(w.httpResCode))
	}

	http2encodeHeaders(enc, w.h, w.trailers)

	if w.contentType != "" {
		http2encKV(enc, "content-type", w.contentType)
	}
	if w.contentLength != "" {
		http2encKV(enc, "content-length", w.contentLength)
	}
	if w.date != "" {
		http2encKV(enc, "date", w.date)
	}

	headerBlock := buf.Bytes()
	if len(headerBlock) == 0 && w.trailers == nil {
		panic("unexpected empty hpack")
	}

	return http2splitHeaderBlock(ctx, headerBlock, w.writeHeaderBlock)
}

func (w *http2writeResHeaders) writeHeaderBlock(ctx http2writeContext, frag []byte, firstFrag, lastFrag bool) error {
	if firstFrag {
		return ctx.Framer().WriteHeaders(http2HeadersFrameParam{
			StreamID:      w.streamID,
			BlockFragment: frag,
			EndStream:     w.endStream,
			EndHeaders:    lastFrag,
		})
	} else {
		return ctx.Framer().WriteContinuation(w.streamID, lastFrag, frag)
	}
}

// writePushPromise是一个写入PUSH_承诺和0+连续帧的请求。
type http2writePushPromise struct {
	streamID uint32   // 推送流
	method   string   // for:method 
	url      *url.URL // for:scheme，：authority，：path 
	h        Header

	// 为推送流创建ID。这在serveG上运行，就在
	// 框架被写入之前。返回的ID被复制到promisedID。
	allocatePromisedID func() (uint32, error)
	promisedID         uint32
}

func (w *http2writePushPromise) staysWithinBuffer(max int) bool {
	// 待办事项：参见书面说明。StaysWithBuffer 
	return false
}

func (w *http2writePushPromise) writeFrame(ctx http2writeContext) error {
	enc, buf := ctx.HeaderEncoder()
	buf.Reset()

	http2encKV(enc, ":method", w.method)
	http2encKV(enc, ":scheme", w.url.Scheme)
	http2encKV(enc, ":authority", w.url.Host)
	http2encKV(enc, ":path", w.url.RequestURI())
	http2encodeHeaders(enc, w.h, nil)

	headerBlock := buf.Bytes()
	if len(headerBlock) == 0 {
		panic("unexpected empty hpack")
	}

	return http2splitHeaderBlock(ctx, headerBlock, w.writeHeaderBlock)
}

func (w *http2writePushPromise) writeHeaderBlock(ctx http2writeContext, frag []byte, firstFrag, lastFrag bool) error {
	if firstFrag {
		return ctx.Framer().WritePushPromise(http2PushPromiseParam{
			StreamID:      w.streamID,
			PromiseID:     w.promisedID,
			BlockFragment: frag,
			EndHeaders:    lastFrag,
		})
	} else {
		return ctx.Framer().WriteContinuation(w.streamID, lastFrag, frag)
	}
}

type http2write100ContinueHeadersFrame struct {
	streamID uint32
}

func (w http2write100ContinueHeadersFrame) writeFrame(ctx http2writeContext) error {
	enc, buf := ctx.HeaderEncoder()
	buf.Reset()
	http2encKV(enc, ":status", "100")
	return ctx.Framer().WriteHeaders(http2HeadersFrameParam{
		StreamID:      w.streamID,
		BlockFragment: buf.Bytes(),
		EndStream:     false,
		EndHeaders:    true,
	})
}

func (w http2write100ContinueHeadersFrame) staysWithinBuffer(max int) bool {
	// 邋遢但保守：
	return 9+2*(len(":status")+len("100")) <= max
}

type http2writeWindowUpdate struct {
	streamID uint32 // 或0表示连接级别
	n        uint32
}

func (wu http2writeWindowUpdate) staysWithinBuffer(max int) bool { return http2frameHeaderLen+4 <= max }

func (wu http2writeWindowUpdate) writeFrame(ctx http2writeContext) error {
	return ctx.Framer().WriteWindowUpdate(wu.streamID, wu.n)
}

// 编码头对http进行编码。头球。如果keys不是nil，那么（k，h[k]）
// 仅当k在keys中时才被编码。
func http2encodeHeaders(enc *hpack.Encoder, h Header, keys []string) {
	if keys == nil {
		sorter := http2sorterPool.Get().(*http2sorter)
		// 此处使用延迟，因为从
		// 分拣机返回的密钥。Keys方法仅在分类器
		// 返回之前有效：
		defer http2sorterPool.Put(sorter)
		keys = sorter.Keys(h)
	}
	for _, k := range keys {
		vv := h[k]
		k, ascii := http2lowerHeader(k)
		if !ascii {
			// 跳过写入无效的头。根据RFC 7540第8.1.2节，标题
			// 字段名必须是ASCII字符（就像在HTTP/1.x中一样）。
			continue
		}
		if !http2validWireHeaderFieldName(k) {
			// 跳过它作为备份偏执狂。根据
			// golang。org/issue/14048，这些应该
			// 已经在更高级别被拒绝。
			continue
		}
		isTE := k == "transfer-encoding"
		for _, v := range vv {
			if !httpguts.ValidHeaderFieldValue(v) {
				// TODO:返回错误？戈朗。org/issue/14048 
				// 暂时省略它。
				continue
			}
			// TODO:更多“8.1.2.2连接特定头字段”
			if isTE && v != "trailers" {
				continue
			}
			http2encKV(enc, k, v)
		}
	}
}

// WriteScheduler是HTTP/2写调度程序实现的接口。
// 永远不会同时调用方法。
type http2WriteScheduler interface {
	// OpenStream在写调度程序中打开一个新流。
	// 使用streamID=0或streamID为
	// 的streamID调用此函数是非法的，调用可能会死机。
	OpenStream(streamID uint32, options http2OpenStreamOptions)

	// CloseStream关闭写入计划程序中的流。
	// 此流上排队的任何帧都应被丢弃。在未打开的流
	// /上调用此函数是非法的，调用可能会导致恐慌。
	CloseStream(streamID uint32)

	// AdjustStream调整给定流的优先级。在尚未打开或已关闭的流上，这可能被称为
	// 。请注意，
	// RFC 7540允许在任何状态的流上发送优先级帧。请参阅：
	// https:
	AdjustStream(streamID uint32, priority http2PriorityParam)

	// 在调度程序中推送一个帧。在大多数情况下，这不会用wr调用
	// 。StreamID（）=0，除非该流当前处于打开状态。
	// 异常之一是RST_流帧，它可以在空闲或关闭的流上发送。
	Push(wr http2FrameWriteRequest)

	// Pop退出下一个要写入的帧的队列。如果无法写入任何帧
	// 则返回false。具有给定wr的帧。StreamID（）以相同的
	// 顺序弹出，但RST_流帧除外。除CloseStream外，不应丢弃任何帧。
	Pop() (wr http2FrameWriteRequest, ok bool)
}

// OpenStreamOptions为WriteScheduler指定额外选项。OpenStream。
type http2OpenStreamOptions struct {
	// 如果流是由客户端启动的，则PusherID为零。否则，
	// PusherID为推送新打开的流的流命名。
	PusherID uint32
}

// FrameWriteRequest是一个写帧的请求。
type http2FrameWriteRequest struct {
	// write是在
	// WriteScheduler选择此帧进行写入后执行写入的接口值。write 
	// 函数都是在write中定义的。去
	write http2writeFramer

	// 流是将写入此帧的流。
	// nil用于PING和设置等非流帧。
	// 对于使用拖缆错误的RST_流，为零。改为流线型场。
	stream *http2stream

	// done，如果非nil，则必须是一个缓冲通道，带有空间，用于
	// 1消息，并在写入帧时发送write返回值（或
	// 早期错误）。
	done chan error
}

// StreamID返回此帧将写入的流的id。
// 0用于PING和设置等非流帧。
func (wr http2FrameWriteRequest) StreamID() uint32 {
	if wr.stream == nil {
		if se, ok := wr.write.(http2StreamError); ok {
			// /（*服务器连接）。resetStream不设置
			// 流，因为它不一定有
			// 流。所以这种特殊情况下写
			// 消息。
			return se.StreamID
		}
		return 0
	}
	return wr.stream.id
}

// isControl报告wr是否为MaxQueuedControlFrames的控制帧
// 目的。这包括非流帧和RST_流帧。
func (wr http2FrameWriteRequest) isControl() bool {
	return wr.stream == nil
}

// DataSize返回写入整个帧必须使用的流控制字节数。对于非数据帧，这是0。
func (wr http2FrameWriteRequest) DataSize() int {
	if wd, ok := wr.write.(*http2writeData); ok {
		return len(wd.p)
	}
	return 0
}

// Consume消耗此帧中的最小（n，可用）字节，其中可用
// 是流上可用的流控制字节数。Consume返回
// 0、1或2帧，其中整数返回值给出返回的帧数
// 。
// 
// 如果流控制阻止消耗任何字节，则返回（，，0）。如果
// 整个帧被消耗，则返回（wr，1）。否则，此
// 返回（consumed，rest，2），其中'consumed'包含已使用的字节，而
// /'rest'包含剩余的字节。消耗的字节从
// 基础流的流控制预算中扣除。
func (wr http2FrameWriteRequest) Consume(n int32) (http2FrameWriteRequest, http2FrameWriteRequest, int) {
	var empty http2FrameWriteRequest

	// 非数据帧总是全部消耗。
	wd, ok := wr.write.(*http2writeData)
	if !ok || len(wd.p) == 0 {
		return wr, empty, 1
	}

	// 应用限制后可能需要拆分。
	allowed := wr.stream.flow.available()
	if n < allowed {
		allowed = n
	}
	if wr.stream.sc.maxFrameSize < allowed {
		allowed = wr.stream.sc.maxFrameSize
	}
	if allowed <= 0 {
		return empty, empty, 0
	}
	if len(wd.p) > int(allowed) {
		wr.stream.flow.take(allowed)
		consumed := http2FrameWriteRequest{
			stream: wr.stream,
			write: &http2writeData{
				streamID: wd.streamID,
				p:        wd.p[:allowed],
				// 即使原始设置了endStream，仍然有字节剩余，因为len（wd.p）>允许，所以我们知道endStream为false。
				endStream: false,
			},
			// 我们的调用者正在最后一个数据帧上阻塞，而不是
			// 这个中间帧，所以不需要等待。
			done: nil,
		}
		rest := http2FrameWriteRequest{
			stream: wr.stream,
			write: &http2writeData{
				streamID:  wd.streamID,
				p:         wd.p[allowed:],
				endStream: wd.endStream,
			},
			done: wr.done,
		}
		return consumed, rest, 2
	}

	// 整个框架被消耗。
	// NB:此强制转换不能溢出，因为允许的值为<=math。MaxInt32。wen dang
	wr.stream.flow.take(int32(len(wd.p)))
	return wr, empty, 1
}

func (wr http2FrameWriteRequest) String() string {
	var des string
	if s, ok := wr.write.(fmt.Stringer); ok {
		des = s.String()
	} else {
		des = fmt.Sprintf("%T", wr.write)
	}
	return fmt.Sprintf("[FrameWriteRequest stream=%d, ch=%v, writer=%v]", wr.StreamID(), wr.done != nil, des)
}

// replyToWriter向wr发送错误。完成，如果发送必须阻止
// 则此操作无效。完成是零。
func (wr *http2FrameWriteRequest) replyToWriter(err error) {
	if wr.done == nil {
		return
	}
	select {
	case wr.done <- err:
	default:
		panic(fmt.Sprintf("unbuffered done channel passed in for type %T", wr.write))
	}
	wr.write = nil // 防止使用（假设在wr.done send之后被污染）
}

// WriteScheduler的实现使用writeQueue。
type http2writeQueue struct {
	s []http2FrameWriteRequest
}

func (q *http2writeQueue) empty() bool { return len(q.s) == 0 }

func (q *http2writeQueue) push(wr http2FrameWriteRequest) {
	q.s = append(q.s, wr)
}

func (q *http2writeQueue) shift() http2FrameWriteRequest {
	if len(q.s) == 0 {
		panic("invalid use of queue")
	}
	wr := q.s[0]
	// 待办事项：少复制快乐队列。
	copy(q.s, q.s[1:])
	q.s[len(q.s)-1] = http2FrameWriteRequest{}
	q.s = q.s[:len(q.s)-1]
	return wr
}

// consume从q.s[0]最多消耗n个字节。如果帧
// 已完全消耗，则会将其从队列中删除。如果部分使用了
// 帧，则保留该帧，并删除已使用的
// 字节。如果消耗了任何字节，则返回true。
func (q *http2writeQueue) consume(n int32) (http2FrameWriteRequest, bool) {
	if len(q.s) == 0 {
		return http2FrameWriteRequest{}, false
	}
	consumed, rest, numresult := q.s[0].Consume(n)
	switch numresult {
	case 0:
		return http2FrameWriteRequest{}, false
	case 1:
		q.shift()
	case 2:
		q.s[0] = rest
	}
	return consumed, true
}

type http2writeQueuePool []*http2writeQueue

// put将未使用的writeQueue插入池中。

// put将未使用的writeQueue插入池中。
func (p *http2writeQueuePool) put(q *http2writeQueue) {
	for i := range q.s {
		q.s[i] = http2FrameWriteRequest{}
	}
	q.s = q.s[:0]
	*p = append(*p, q)
}

// get返回一个空的writeQueue。
func (p *http2writeQueuePool) get() *http2writeQueue {
	ln := len(*p)
	if ln == 0 {
		return new(http2writeQueue)
	}
	x := ln - 1
	q := (*p)[x]
	(*p)[x] = nil
	*p = (*p)[:x]
	return q
}

// RFC 7540，第5.3.5节：默认权重为16。
const http2priorityDefaultWeight = 15 // 16=15+1 

// priorityWriteScheduler配置priorityWriteScheduler。
type http2PriorityWriteSchedulerConfig struct {
	// MaxClosedNodesTree控制要在优先级树中保留的最大关闭流数。将其设置为零会以性能为代价节省少量
	// 内存。
	// 
	// 参见RFC 7540，第5.3.4节：
	// /“当优先顺序
	// 信息……正在传输时，流可能会关闭……这可能会产生次优的
	// 优先顺序，因为流可能被赋予与预期不同的优先顺序
	// 为避免这些问题，端点
	// 应该保留流流
	// 关闭后一段时间内的优先级状态。国家保留的时间越长，
	// 为流分配了不正确或默认的优先级值。“
	MaxClosedNodesInTree int

	// maxidlenodesinctree控制在优先级树中保留的最大空闲流数
	// 。将其设置为零会以性能为代价节省少量内存。
	// 
	// 参见RFC 7540，第5.3.4节：
	// 类似地，处于“空闲”状态的流“状态可以被分配
	// 优先级或成为其他流的父级。这允许
	// 在依赖关系树中创建分组节点，这使
	// 优先级的表达更加灵活。空闲流以
	// 默认优先级开始（第5.3.5节）.
	MaxIdleNodesInTree int

	// ThrottleOutOfOrderWrites启用写限制，以帮助确保
	// 数据按优先级顺序传递。这是围绕着
	// 流B依赖于流a，并且两个流都将调用Write 
	// 来对数据帧进行排队的竞争而进行的。如果B赢了比赛，一个天真的调度器会急切地从B写入尽可能多的数据，但这是次优的，因为
	// 是一个更高优先级的流。启用节流功能后，我们编写一个小的
	// 来自B的数据量，以最小化B可以从a窃取的带宽量
	// 
	ThrottleOutOfOrderWrites bool
}

// NewPriorityWriteScheduler构造一个WriteScheduler，通过遵循RFC 7540第5.3节中描述的HTTP/2优先级来调度
// 帧。
// 如果cfg为nil，则使用默认选项。
func http2NewPriorityWriteScheduler(cfg *http2PriorityWriteSchedulerConfig) http2WriteScheduler {
	if cfg == nil {
		// 有关这些默认值的理由，请参阅：
		// https:
		cfg = &http2PriorityWriteSchedulerConfig{
			MaxClosedNodesInTree:     10,
			MaxIdleNodesInTree:       10,
			ThrottleOutOfOrderWrites: false,
		}
	}

	ws := &http2priorityWriteScheduler{
		nodes:                make(map[uint32]*http2priorityNode),
		maxClosedNodesInTree: cfg.MaxClosedNodesInTree,
		maxIdleNodesInTree:   cfg.MaxIdleNodesInTree,
		enableWriteThrottle:  cfg.ThrottleOutOfOrderWrites,
	}
	ws.nodes[0] = &ws.root
	if cfg.ThrottleOutOfOrderWrites {
		ws.writeThrottleLimit = 1024
	} else {
		ws.writeThrottleLimit = math.MaxInt32
	}
	return ws
}

type http2priorityNodeState int

const (
	http2priorityNodeOpen http2priorityNodeState = iota
	http2priorityNodeClosed
	http2priorityNodeIdle
)

// priorityNode是HTTP/2优先级树中的节点。
// 每个节点都与一个流ID相关联。
// 请参阅RFC 7540，第5.3节。
type http2priorityNode struct {
	q            http2writeQueue        // 要写入流的挂起帧队列
	id           uint32                 // id，或0表示树的根
	weight       uint8                  // 实际权重为权重+1，因此该值位于[1256]
	state        http2priorityNodeState // 打开|关闭|空闲
	bytes        int64                  // 此节点写入的字节数，或者0如果关闭
	subtreeBytes int64                  // 此子树中所有节点的总和（node.bytes）

	// 这些链接构成优先级树。
	parent     *http2priorityNode
	kids       *http2priorityNode // 孩子列表的开始
	prev, next *http2priorityNode // 兄弟姐妹的双链接列表
}

func (n *http2priorityNode) setParent(parent *http2priorityNode) {
	if n == parent {
		panic("setParent to self")
	}
	if n.parent == parent {
		return
	}
	// 取消与当前家长的链接。
	if parent := n.parent; parent != nil {
		if n.prev == nil {
			parent.kids = n.next
		} else {
			n.prev.next = n.next
		}
		if n.next != nil {
			n.next.prev = n.prev
		}
	}
	// 链接到新的家长。
	// 如果parent=nil，则从树中删除n。
	// 始终在父项的开头插入。孩子们（这是WalkReadyOrder假设的）。
	n.parent = parent
	if parent == nil {
		n.next = nil
		n.prev = nil
	} else {
		n.next = parent.kids
		n.prev = nil
		if n.next != nil {
			n.next.prev = n
		}
		parent.kids = n
	}
}

func (n *http2priorityNode) addBytes(b int64) {
	n.bytes += b
	for ; n != nil; n = n.parent {
		n.subtreeBytes += b
	}
}

// WalkReadyOrder以优先级顺序在树上迭代，使用非空写入队列为每个节点调用f。当f返回true时，此函数返回true，
// 行走停止。tmp用作排序的暂存空间。
// 
// f（n，openParent）接受两个参数：要访问的节点n和一个为真的布尔值
// 如果n的任何祖先p仍然打开（忽略根节点）。AbDefg
func (n *http2priorityNode) walkReadyInOrder(openParent bool, tmp *[]*http2priorityNode, f func(*http2priorityNode, bool) bool) bool {
	if !n.q.empty() && f(n, openParent) {
		return true
	}
	if n.kids == nil {
		return false
	}

	if n.id != 0 {
		openParent = openParent || (n.state == http2priorityNodeOpen)
	}

	// 常见情况：只有一个孩子或所有孩子的体重相同。
	// 有些客户不使用权重；其他客户端（如web浏览器）
	// 主要使用线性优先级树。
	w := n.kids.weight
	needSort := false
	for k := n.kids.next; k != nil; k = k.next {
		if k.weight != w {
			needSort = true
			break
		}
	}
	if !needSort {
		for k := n.kids; k != nil; k = k.next {
			if k.walkReadyInOrder(openParent, tmp, f) {
				return true
			}
		}
		return false
	}

	// 不常见情况：对子节点排序。我们从父级
	// 中删除子级，然后在排序后重新插入，这样我们就可以在将来的排序调用中重用tmp。
	*tmp = (*tmp)[:0]
	for n.kids != nil {
		*tmp = append(*tmp, n.kids)
		n.kids.setParent(nil)
	}
	sort.Sort(http2sortPriorityNodeSiblings(*tmp))
	for i := len(*tmp) - 1; i >= 0; i-- {
		(*tmp)[i].setParent(n) // 在n.kids的开头插入setParent 
	}
	for k := n.kids; k != nil; k = k.next {
		if k.walkReadyInOrder(openParent, tmp, f) {
			return true
		}
	}
	return false
}

type http2sortPriorityNodeSiblings []*http2priorityNode

func (z http2sortPriorityNodeSiblings) Len() int { return len(z) }

func (z http2sortPriorityNodeSiblings) Swap(i, k int) { z[i], z[k] = z[k], z[i] }

func (z http2sortPriorityNodeSiblings) Less(i, k int) bool {
	// 首选发送的字节数相对于其权重较少的子树。
	// 参见第5.3.2节和第5.3.4节。
	wi, bi := float64(z[i].weight+1), float64(z[i].subtreeBytes)
	wk, bk := float64(z[k].weight+1), float64(z[k].subtreeBytes)
	if bi == 0 && bk == 0 {
		return wi >= wk
	}
	if bk == 0 {
		return false
	}
	return bi/bk <= wi/wk
}

type http2priorityWriteScheduler struct {
	// root是优先级树的根，其中root。id=0。
	// 根队列控制未与任何流关联的帧。
	root http2priorityNode

	// 节点将流ID映射到优先级树节点。
	nodes map[uint32]*http2priorityNode

	// maxID是节点中的最大流id。
	maxID uint32

	// 已关闭或空闲但保留在
	// 树中的节点列表，以改进优先级。当长度超过
	// maxClosedNodesInTree或maxIdleNodesInTree时，旧节点将被丢弃。
	closedNodes, idleNodes []*http2priorityNode

	// 从配置中。
	maxClosedNodesInTree int
	maxIdleNodesInTree   int
	writeThrottleLimit   int32
	enableWriteThrottle  bool

	// tmp是priorityNode的暂存空间。WalkReady以减少分配。
	tmp []*http2priorityNode

	// 供重用的空队列池。
	queuePool http2writeQueuePool
}

func (ws *http2priorityWriteScheduler) OpenStream(streamID uint32, options http2OpenStreamOptions) {
	// 流当前可能处于空闲状态，但无法打开或关闭。
	if curr := ws.nodes[streamID]; curr != nil {
		if curr.state != http2priorityNodeIdle {
			panic(fmt.Sprintf("stream %d already opened", streamID))
		}
		curr.state = http2priorityNodeOpen
		return
	}

	// RFC 7540，第5.3.5节：
	// “所有流最初都分配了对流0x0的非排他依赖关系。
	// 推送流最初依赖于它们的关联流。在这两种情况下，
	// 流的默认权重均为16。”
	parent := ws.nodes[options.PusherID]
	if parent == nil {
		parent = &ws.root
	}
	n := &http2priorityNode{
		q:      *ws.queuePool.get(),
		id:     streamID,
		weight: http2priorityDefaultWeight,
		state:  http2priorityNodeOpen,
	}
	n.setParent(parent)
	ws.nodes[streamID] = n
	if streamID > ws.maxID {
		ws.maxID = streamID
	}
}

func (ws *http2priorityWriteScheduler) CloseStream(streamID uint32) {
	if streamID == 0 {
		panic("violation of WriteScheduler interface: cannot close stream 0")
	}
	if ws.nodes[streamID] == nil {
		panic(fmt.Sprintf("violation of WriteScheduler interface: unknown stream %d", streamID))
	}
	if ws.nodes[streamID].state != http2priorityNodeOpen {
		panic(fmt.Sprintf("violation of WriteScheduler interface: stream %d already closed", streamID))
	}

	n := ws.nodes[streamID]
	n.state = http2priorityNodeClosed
	n.addBytes(-n.bytes)

	q := n.q
	ws.queuePool.put(&q)
	n.q.s = nil
	if ws.maxClosedNodesInTree > 0 {
		ws.addClosedOrIdleNode(&ws.closedNodes, ws.maxClosedNodesInTree, n)
	} else {
		ws.removeNode(n)
	}
}

func (ws *http2priorityWriteScheduler) AdjustStream(streamID uint32, priority http2PriorityParam) {
	if streamID == 0 {
		panic("adjustPriority on root")
	}

	// 如果streamID不存在，有两种情况：
	// /-一个已被删除的封闭流（ID<=maxID）
	// /-一个正在用于“分组”的空闲流（ID>maxID）
	n := ws.nodes[streamID]
	if n == nil {
		if streamID <= ws.maxID || ws.maxIdleNodesInTree == 0 {
			return
		}
		ws.maxID = streamID
		n = &http2priorityNode{
			q:      *ws.queuePool.get(),
			id:     streamID,
			weight: http2priorityDefaultWeight,
			state:  http2priorityNodeIdle,
		}
		n.setParent(&ws.root)
		ws.nodes[streamID] = n
		ws.addClosedOrIdleNode(&ws.idleNodes, ws.maxIdleNodesInTree, n)
	}

	// 第5.3.1节：对当前不在树中的流的依赖
	// 导致该流被赋予默认优先级（第5.3.5节）。
	parent := ws.nodes[priority.StreamDep]
	if parent == nil {
		n.setParent(&ws.root)
		n.weight = http2priorityDefaultWeight
		return
	}

	// 如果客户端试图将节点设置为其自己的父节点，则忽略。
	if n == parent {
		return
	}

	// 第5.3.3节：
	// “如果一个流依赖于它自己的一个依赖项，则
	// 以前的依赖项流首先被移动到依赖于
	// 重新设置优先级的流的前一个父项。移动的依赖项保留
	// 其权重。”
	// 
	// 即：如果父项依赖于n，则将父项移动到依赖于n.parent。
	for x := parent.parent; x != nil; x = x.parent {
		if x == n {
			parent.setParent(n.parent)
			break
		}
	}

	// 第5.3.3节：独占标志导致流成为其父流的唯一
	// 依赖项，导致其他依赖项成为
	// 依赖于独占流。
	if priority.Exclusive {
		k := parent.kids
		for k != nil {
			next := k.next
			if k != n {
				k.setParent(n)
			}
			k = next
		}
	}

	n.setParent(parent)
	n.weight = priority.Weight
}

func (ws *http2priorityWriteScheduler) Push(wr http2FrameWriteRequest) {
	var n *http2priorityNode
	if id := wr.StreamID(); id == 0 {
		n = &ws.root
	} else {
		n = ws.nodes[id]
		if n == nil {
			// id是一个空闲或关闭的流。wr不应是标头或
			// 数据帧。然而，wr可以是RST_流。在本例中，我们将wr推到根上，而不是创建一个新的priorityNode，因为RST_流很小，流的优先级未知。见第17919期。
			if wr.DataSize() > 0 {
				panic("add DATA on non-open stream")
			}
			n = &ws.root
		}
	}
	n.q.push(wr)
}

func (ws *http2priorityWriteScheduler) Pop() (wr http2FrameWriteRequest, ok bool) {
	ws.root.walkReadyInOrder(false, &ws.tmp, func(n *http2priorityNode, openParent bool) bool {
		limit := int32(math.MaxInt32)
		if openParent {
			limit = ws.writeThrottleLimit
		}
		wr, ok = n.q.consume(limit)
		if !ok {
			return false
		}
		n.addBytes(int64(wr.DataSize()))
		// 如果B依赖于A，且B持续有可用数据，但A不可用，则逐渐增加节流限制，以允许B从A窃取越来越多的带宽。
		if openParent {
			ws.writeThrottleLimit += 1024
			if ws.writeThrottleLimit < 0 {
				ws.writeThrottleLimit = math.MaxInt32
			}
		} else if ws.enableWriteThrottle {
			ws.writeThrottleLimit = 1024
		}
		return true
	})
	return wr, ok
}

func (ws *http2priorityWriteScheduler) addClosedOrIdleNode(list *[]*http2priorityNode, maxSize int, n *http2priorityNode) {
	if maxSize == 0 {
		return
	}
	if len(*list) == maxSize {
		// 删除最旧的节点，然后向左移动。
		ws.removeNode((*list)[0])
		x := (*list)[1:]
		copy(*list, x)
		*list = (*list)[:len(x)]
	}
	*list = append(*list, n)
}

func (ws *http2priorityWriteScheduler) removeNode(n *http2priorityNode) {
	for k := n.kids; k != nil; k = k.next {
		k.setParent(n.parent)
	}
	n.setParent(nil)
	delete(ws.nodes, n.id)
}

// NewRandomWriteScheduler构造一个忽略HTTP/2的WriteScheduler 
// 优先级。设置和PING等控制帧写入数据
// 帧之前，但如果没有控制帧排队，且多个流已排队
// 头或数据帧，Pop会任意选择一个就绪流。
func http2NewRandomWriteScheduler() http2WriteScheduler {
	return &http2randomWriteScheduler{sq: make(map[uint32]*http2writeQueue)}
}

type http2randomWriteScheduler struct {
	// 零是与特定流无关的帧。
	zero http2writeQueue

	// sq包含特定于流的队列，由流ID键控。
	// 当流空闲、关闭或清空时，将从映射中删除
	// 流。
	sq map[uint32]*http2writeQueue

	// 供重用的空队列池。
	queuePool http2writeQueuePool
}

func (ws *http2randomWriteScheduler) OpenStream(streamID uint32, options http2OpenStreamOptions) {
	// 无操作：不跟踪空闲流
}

func (ws *http2randomWriteScheduler) CloseStream(streamID uint32) {
	q, ok := ws.sq[streamID]
	if !ok {
		return
	}
	delete(ws.sq, streamID)
	ws.queuePool.put(q)
}

func (ws *http2randomWriteScheduler) AdjustStream(streamID uint32, priority http2PriorityParam) {
	// 无操作：忽略优先级
}

func (ws *http2randomWriteScheduler) Push(wr http2FrameWriteRequest) {
	if wr.isControl() {
		ws.zero.push(wr)
		return
	}
	id := wr.StreamID()
	q, ok := ws.sq[id]
	if !ok {
		q = ws.queuePool.get()
		ws.sq[id] = q
	}
	q.push(wr)
}

func (ws *http2randomWriteScheduler) Pop() (http2FrameWriteRequest, bool) {
	// 首先控制和重新设置流帧。
	if !ws.zero.empty() {
		return ws.zero.shift(), true
	}
	// 迭代所有非空闲流，直到找到一个可以使用的流。
	for streamID, q := range ws.sq {
		if wr, ok := q.consume(math.MaxInt32); ok {
			if q.empty() {
				delete(ws.sq, streamID)
				ws.queuePool.put(q)
			}
			return wr, true
		}
	}
	return http2FrameWriteRequest{}, false
}
